From f9ec3cbca0f05fd9640bbd5cd3e21942c4512d3d Mon Sep 17 00:00:00 2001
From: Filipe David Manana
Date: Sun, 26 Sep 2010 11:58:45 +0100
Subject: httpc: allow streaming of PUT and POST request bodies
This is a must when uploading large bodies that are to large to store
in a string or binary.
Besides a string or binary, a body can now be a function and
an accumulator.
Example:
-module(httpc_post_stream_test).
-compile(export_all).
-define(LEN, 1024 * 1024).
prepare_data() ->
{ok, Fd} = file:open("test_data.dat", [binary, write]),
ok = file:write(Fd, lists:duplicate(?LEN, "1")),
ok = file:close(Fd).
test() ->
inets:start(),
ok = prepare_data(),
{ok, Fd1} = file:open("test_data.dat", [binary, read]),
BodyFun = fun(Fd) ->
case file:read(Fd, 512) of
eof ->
eof;
{ok, Data} ->
{ok, Data, Fd}
end
end,
{ok, {{_,200,_}, _, _}} = httpc:request(post, {"http://localhost:8888",
[{"content-length", integer_to_list(?LEN)}], "text/plain", {BodyFun, Fd1}}, [], []),
ok = file:close(Fd1).
---
lib/inets/doc/src/httpc.xml | 4 +-
lib/inets/src/http_client/httpc.erl | 4 +-
lib/inets/src/http_client/httpc_request.erl | 64 ++++++++++++++++++++++-------
lib/inets/test/httpc_SUITE.erl | 40 ++++++++++++++++++
4 files changed, 96 insertions(+), 16 deletions(-)
diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml
index 9c8df28fec..df333074cd 100644
--- a/lib/inets/doc/src/httpc.xml
+++ b/lib/inets/doc/src/httpc.xml
@@ -89,7 +89,9 @@ headers() = [header()]
header() = {field(), value()}
field() = string()
value() = string()
-body() = string() | binary()
+body() = string() | binary() | {fun(acc()) -> send_fun_result(), acc()}
+send_fun_result() = eof | {ok, iolist(), acc()}
+acc() = term()
filename() = string()
]]>
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index 851364001c..b82a9db4c9 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -126,7 +126,9 @@ request(Url, Profile) ->
%% Header = {Field, Value}
%% Field = string()
%% Value = string()
-%% Body = string() | binary() - HTLM-code
+%% Body = string() | binary() | {fun(SendAcc) -> SendFunResult, SendAcc} - HTLM-code
+%% SendFunResult = eof | {ok, iolist(), NewSendAcc}
+%% SendAcc = NewSendAcc = term()
%%
%% Description: Sends a HTTP-request. The function can be both
%% syncronus and asynchronous in the later case the function will
diff --git a/lib/inets/src/http_client/httpc_request.erl b/lib/inets/src/http_client/httpc_request.erl
index d4df97ad40..5386d1eb4a 100644
--- a/lib/inets/src/http_client/httpc_request.erl
+++ b/lib/inets/src/http_client/httpc_request.erl
@@ -101,15 +101,41 @@ send(SendAddr, Socket, SocketType,
end,
Version = HttpOptions#http_options.version,
- Message = [method(Method), " ", Uri, " ",
- version(Version), ?CRLF,
- headers(FinalHeaders, Version), ?CRLF, Body],
+ do_send_body(SocketType, Socket, Method, Uri, Version, FinalHeaders, Body).
+
+do_send_body(SocketType, Socket, Method, Uri, Version, Headers, {DataFun, Acc})
+ when is_function(DataFun, 1) ->
+ case do_send_body(SocketType, Socket, Method, Uri, Version, Headers, []) of
+ ok ->
+ data_fun_loop(SocketType, Socket, DataFun, Acc);
+ Error ->
+ Error
+ end;
+
+do_send_body(SocketType, Socket, Method, Uri, Version, Headers, Body) ->
+ Message = [method(Method), " ", Uri, " ",
+ version(Version), ?CRLF,
+ headers(Headers, Version), ?CRLF, Body],
?hcrd("send", [{message, Message}]),
-
http_transport:send(SocketType, Socket, lists:append(Message)).
+data_fun_loop(SocketType, Socket, DataFun, Acc) ->
+ case DataFun(Acc) of
+ eof ->
+ ok;
+ {ok, Data, NewAcc} ->
+ DataBin = iolist_to_binary(Data),
+ ?hcrd("send", [{message, DataBin}]),
+ case http_transport:send(SocketType, Socket, DataBin) of
+ ok ->
+ data_fun_loop(SocketType, Socket, DataFun, NewAcc);
+ Error ->
+ Error
+ end
+ end.
+
%%-------------------------------------------------------------------------
%% is_idempotent(Method) ->
@@ -161,7 +187,6 @@ is_client_closing(Headers) ->
%%%========================================================================
post_data(Method, Headers, {ContentType, Body}, HeadersAsIs)
when (Method =:= post) orelse (Method =:= put) ->
- ContentLength = body_length(Body),
NewBody = case Headers#http_request_h.expect of
"100-continue" ->
"";
@@ -170,14 +195,22 @@ post_data(Method, Headers, {ContentType, Body}, HeadersAsIs)
end,
NewHeaders = case HeadersAsIs of
- [] ->
- Headers#http_request_h{'content-type' =
- ContentType,
- 'content-length' =
- ContentLength};
- _ ->
- HeadersAsIs
- end,
+ [] ->
+ Headers#http_request_h{
+ 'content-type' = ContentType,
+ 'content-length' = case body_length(Body) of
+ undefined ->
+ % on upload streaming the caller must give a
+ % value to the Content-Length header
+ % (or use chunked Transfer-Encoding)
+ Headers#http_request_h.'content-length';
+ Len when is_list(Len) ->
+ Len
+ end
+ };
+ _ ->
+ HeadersAsIs
+ end,
{NewHeaders, NewBody};
@@ -190,7 +223,10 @@ body_length(Body) when is_binary(Body) ->
integer_to_list(size(Body));
body_length(Body) when is_list(Body) ->
- integer_to_list(length(Body)).
+ integer_to_list(length(Body));
+
+body_length({DataFun, _Acc}) when is_function(DataFun, 1) ->
+ undefined.
method(Method) ->
http_util:to_upper(atom_to_list(Method)).
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 902e440c80..6947f75b3d 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -77,6 +77,7 @@ all(suite) ->
http_head,
http_get,
http_post,
+ http_post_streaming,
http_dummy_pipe,
http_inets_pipe,
http_trace,
@@ -423,6 +424,45 @@ http_post(Config) when is_list(Config) ->
{skip, "Failed to start local http-server"}
end.
+%%-------------------------------------------------------------------------
+http_post_streaming(doc) ->
+ ["Test streaming http post request against local server. We"
+ " only care about the client side of the the post. The server"
+ " script will not actually use the post data."];
+http_post_streaming(suite) ->
+ [];
+http_post_streaming(Config) when is_list(Config) ->
+ case ?config(local_server, Config) of
+ ok ->
+ Port = ?config(local_port, Config),
+ URL = case test_server:os_type() of
+ {win32, _} ->
+ ?URL_START ++ integer_to_list(Port) ++
+ "/cgi-bin/cgi_echo.exe";
+ _ ->
+ ?URL_START ++ integer_to_list(Port) ++
+ "/cgi-bin/cgi_echo"
+ end,
+ %% Cgi-script expects the body length to be 100
+ BodyFun = fun(0) ->
+ eof;
+ (LenLeft) ->
+ {ok, lists:duplicate(10, "1"), LenLeft - 10}
+ end,
+
+ {ok, {{_,200,_}, [_ | _], [_ | _]}} =
+ httpc:request(post, {URL,
+ [{"expect", "100-continue"}, {"content-length", "100"}],
+ "text/plain", {BodyFun, 100}}, [], []),
+
+ {ok, {{_,504,_}, [_ | _], []}} =
+ httpc:request(post, {URL,
+ [{"expect", "100-continue"}, {"content-length", "10"}],
+ "text/plain", {BodyFun, 10}}, [], []);
+ _ ->
+ {skip, "Failed to start local http-server"}
+ end.
+
%%-------------------------------------------------------------------------
http_emulate_lower_versions(doc) ->
["Perform request as 0.9 and 1.0 clients."];
--
cgit v1.2.3
From 6951ed1075b8c36d5b6f51e5e5df7bd14602c1d8 Mon Sep 17 00:00:00 2001
From: Filipe David Manana
Date: Tue, 5 Oct 2010 00:26:33 +0100
Subject: httpc: add option to do automatic chunked transfer-encoding
This is specially useful when a client doesn't know in advance the
length of the payload (so that it can't set the
Content-Length header).
Example:
-module(httpc_post_stream_test).
-compile(export_all).
prepare_data() ->
crypto:start(),
{ok, Fd} = file:open("test_data.dat", [binary, write]),
ok = file:write(Fd, lists:duplicate(crypto:rand_uniform(8182, 32768), "1")),
ok = file:close(Fd).
test() ->
inets:start(),
ok = prepare_data(),
{ok, Fd1} = file:open("test_data.dat", [binary, read]),
BodyFun = fun(Fd) ->
case file:read(Fd, 512) of
eof ->
eof;
{ok, Data} ->
{ok, Data, Fd}
end
end,
%% header 'Transfer-Encoding: chunked' is added by httpc
{ok, {{_,200,_}, _, _}} = httpc:request(post, {"http://localhost:8888",
[], "text/plain", {chunkify, BodyFun, Fd1}}, [], []),
ok = file:close(Fd1).
---
lib/inets/doc/src/httpc.xml | 4 +++-
lib/inets/src/http_client/httpc.erl | 34 ++++++++++++++++++++++++++++++----
2 files changed, 33 insertions(+), 5 deletions(-)
diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml
index df333074cd..8b04b4c7f3 100644
--- a/lib/inets/doc/src/httpc.xml
+++ b/lib/inets/doc/src/httpc.xml
@@ -89,7 +89,9 @@ headers() = [header()]
header() = {field(), value()}
field() = string()
value() = string()
-body() = string() | binary() | {fun(acc()) -> send_fun_result(), acc()}
+body() = string() | binary() |
+ {fun(acc()) -> send_fun_result(), acc()} |
+ {chunkify, fun(acc()) -> send_fun_result(), acc()}
send_fun_result() = eof | {ok, iolist(), acc()}
acc() = term()
filename() = string()
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index b82a9db4c9..8cf82df809 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -126,7 +126,8 @@ request(Url, Profile) ->
%% Header = {Field, Value}
%% Field = string()
%% Value = string()
-%% Body = string() | binary() | {fun(SendAcc) -> SendFunResult, SendAcc} - HTLM-code
+%% Body = string() | binary() | {fun(SendAcc) -> SendFunResult, SendAcc} |
+%% {chunkify, fun(SendAcc) -> SendFunResult, SendAcc} - HTLM-code
%% SendFunResult = eof | {ok, iolist(), NewSendAcc}
%% SendAcc = NewSendAcc = term()
%%
@@ -428,11 +429,20 @@ service_info(Pid) ->
handle_request(Method, Url,
{Scheme, UserInfo, Host, Port, Path, Query},
- Headers, ContentType, Body,
+ Headers0, ContentType, Body0,
HTTPOptions0, Options0, Profile) ->
Started = http_util:timestamp(),
- NewHeaders = [{http_util:to_lower(Key), Val} || {Key, Val} <- Headers],
+ NewHeaders0 = [{http_util:to_lower(Key), Val} || {Key, Val} <- Headers0],
+
+ {NewHeaders, Body} = case Body0 of
+ {chunkify, BodyFun, Acc} ->
+ NewHeaders1 = lists:keystore("transfer-encoding", 1,
+ NewHeaders0, {"transfer-encoding", "chunked"}),
+ {NewHeaders1, {chunkify_fun(BodyFun), Acc}};
+ _ ->
+ {NewHeaders0, Body0}
+ end,
try
begin
@@ -456,7 +466,7 @@ handle_request(Method, Url,
abs_uri = Url,
userinfo = UserInfo,
stream = Stream,
- headers_as_is = headers_as_is(Headers, Options),
+ headers_as_is = headers_as_is(Headers0, Options),
socket_opts = SocketOpts,
started = Started},
case httpc_manager:request(Request, profile_name(Profile)) of
@@ -473,6 +483,22 @@ handle_request(Method, Url,
Error
end.
+chunkify_fun(BodyFun) ->
+ fun(eof_body_fun) ->
+ eof;
+ (Acc) ->
+ case BodyFun(Acc) of
+ eof ->
+ {ok, <<"0\r\n\r\n">>, eof_body_fun};
+ {ok, Data, NewAcc} ->
+ Bin = iolist_to_binary(Data),
+ Chunk = [hex_size(Bin), "\r\n", Bin, "\r\n"],
+ {ok, iolist_to_binary(Chunk), NewAcc}
+ end
+ end.
+
+hex_size(Bin) ->
+ hd(io_lib:format("~.16B", [size(Bin)])).
handle_answer(RequestId, false, _) ->
{ok, RequestId};
--
cgit v1.2.3
From 4827d5db5fb2ca10772f70fbb6ad7f7f99285d96 Mon Sep 17 00:00:00 2001
From: Michael Santos
Date: Mon, 21 Feb 2011 13:53:56 -0500
Subject: inets: prevent XSS in error pages
Prevent user controlled input from being interpreted as HTML in error
pages by encoding the reserved HTML characters. The reserved character
set should be safe for displaying data within the body of HTML pages
as outlined here:
http://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
Previously, weird URLs were URI encoded in the error page. This worked
quite well but the URL would be displayed in the HTML in percent encoded
format. There was also a check for URIs that were already escaped (by
the browser) that would fail if the browser sent an URI containing a
"%", e.g.:
w3m "http://localhost:8080/foo?%"
Also encode the HTTP method and version, since it's possible they may be
manipulated:
FOO /index.html HTTP/1.0
GET /index.html foo/1.0
Encode the static messages to prevent characters from being interpreted
as HTML such as "heavy load (>~w processes)".
---
lib/inets/src/http_lib/http_util.erl | 18 ++++++++++++++-
lib/inets/src/http_server/httpd_util.erl | 38 ++++++++++++++++----------------
lib/inets/test/httpd_basic_SUITE.erl | 11 ++++-----
3 files changed, 42 insertions(+), 25 deletions(-)
diff --git a/lib/inets/src/http_lib/http_util.erl b/lib/inets/src/http_lib/http_util.erl
index 4f1147176c..5e6b69ac5e 100644
--- a/lib/inets/src/http_lib/http_util.erl
+++ b/lib/inets/src/http_lib/http_util.erl
@@ -25,7 +25,8 @@
hexlist_to_integer/1, integer_to_hexlist/1,
convert_month/1,
is_hostname/1,
- timestamp/0, timeout/2
+ timestamp/0, timeout/2,
+ html_encode/1
]).
@@ -187,6 +188,13 @@ timeout(Timeout, Started) ->
end.
+html_encode(Chars) ->
+ Reserved = sets:from_list([$&, $<, $>, $\", $', $/]),
+ lists:append(lists:map(fun(Char) ->
+ char_to_html_entity(Char, Reserved)
+ end, Chars)).
+
+
%%%========================================================================
%%% Internal functions
%%%========================================================================
@@ -235,3 +243,11 @@ convert_to_ascii([Num | Reversed], Number)
convert_to_ascii([Num | Reversed], Number)
when (Num > 9) andalso (Num < 16) ->
convert_to_ascii(Reversed, [Num + 55 | Number]).
+
+char_to_html_entity(Char, Reserved) ->
+ case sets:is_element(Char, Reserved) of
+ true ->
+ "" ++ integer_to_list(Char) ++ ";";
+ false ->
+ [Char]
+ end.
diff --git a/lib/inets/src/http_server/httpd_util.erl b/lib/inets/src/http_server/httpd_util.erl
index 789f12652b..c1aff65d5e 100644
--- a/lib/inets/src/http_server/httpd_util.erl
+++ b/lib/inets/src/http_server/httpd_util.erl
@@ -181,7 +181,7 @@ message(304, _URL,_) ->
message(400,none,_) ->
"Your browser sent a query that this server could not understand.";
message(400,Msg,_) ->
- "Your browser sent a query that this server could not understand. "++ maybe_encode(Msg);
+ "Your browser sent a query that this server could not understand. "++ http_util:html_encode(Msg);
message(401,none,_) ->
"This server could not verify that you
are authorized to access the document you
@@ -190,48 +190,48 @@ credentials (e.g., bad password), or your
browser doesn't understand how to supply
the credentials required.";
message(403,RequestURI,_) ->
- "You don't have permission to access "++ maybe_encode(RequestURI) ++" on this server.";
+ "You don't have permission to access "++ http_util:html_encode(RequestURI) ++" on this server.";
message(404,RequestURI,_) ->
- "The requested URL " ++ maybe_encode(RequestURI) ++ " was not found on this server.";
+ "The requested URL " ++ http_util:html_encode(RequestURI) ++ " was not found on this server.";
message(408, Timeout, _) ->
Timeout;
message(412,none,_) ->
- "The requested preconditions where false";
+ "The requested preconditions were false";
message(413, Reason,_) ->
- "Entity: " ++ Reason;
+ "Entity: " ++ http_util:html_encode(Reason);
message(414,ReasonPhrase,_) ->
- "Message "++ ReasonPhrase ++".";
+ "Message "++ http_util:html_encode(ReasonPhrase) ++".";
message(416,ReasonPhrase,_) ->
- ReasonPhrase;
+ http_util:html_encode(ReasonPhrase);
message(500,_,ConfigDB) ->
ServerAdmin=lookup(ConfigDB,server_admin,"unknown@unknown"),
"The server encountered an internal error or "
"misconfiguration and was unable to complete "
"your request.Please contact the server administrator "
- ++ ServerAdmin ++ ", and inform them of the time the error occurred "
+ ++ http_util:html_encode(ServerAdmin) ++ ", and inform them of the time the error occurred "
"and anything you might have done that may have caused the error.";
message(501,{Method, RequestURI, HTTPVersion}, _ConfigDB) ->
if
is_atom(Method) ->
- atom_to_list(Method)++
- " to "++ maybe_encode(RequestURI)++" ("++HTTPVersion++") not supported.";
+ http_util:html_encode(atom_to_list(Method))++
+ " to "++ http_util:html_encode(RequestURI)++" ("++ http_util:html_encode(HTTPVersion)++") not supported.";
is_list(Method) ->
- Method++
- " to "++ maybe_encode(RequestURI)++" ("++HTTPVersion++") not supported."
+ http_util:html_encode(Method)++
+ " to "++ http_util:html_encode(RequestURI)++" ("++ http_util:html_encode(HTTPVersion)++") not supported."
end;
message(503, String, _ConfigDB) ->
- "This service in unavailable due to: "++String.
+ "This service in unavailable due to: "++ http_util:html_encode(String).
maybe_encode(URI) ->
- case lists:member($%, URI) of
- true ->
- URI;
- false ->
- http_uri:encode(URI)
- end.
+ Decoded = try http_uri:decode(URI) of
+ N -> N
+ catch
+ error:_ -> URI
+ end,
+ http_uri:encode(Decoded).
%%convert_rfc_date(Date)->{{YYYY,MM,DD},{HH,MIN,SEC}}
diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl
index dcea200a1a..1cb07c2f5b 100644
--- a/lib/inets/test/httpd_basic_SUITE.erl
+++ b/lib/inets/test/httpd_basic_SUITE.erl
@@ -151,12 +151,13 @@ escaped_url_in_error_body(Config) when is_list(Config) ->
URL = ?URL_START ++ integer_to_list(Port) ++ Path,
EscapedPath = http_uri:encode(Path),
{ok, {404, Body}} = httpc:request(get, {URL, []},
- [{url_encode, true}],
- [{version, "HTTP/1.0"}, {full_result, false}]),
+ [{url_encode, true}, {version, "HTTP/1.0"}],
+ [{full_result, false}]),
EscapedPath = find_URL_path(string:tokens(Body, " ")),
- {ok, {404, Body1}} = httpc:request(get, {URL, []}, [],
- [{version, "HTTP/1.0"}, {full_result, false}]),
- EscapedPath = find_URL_path(string:tokens(Body1, " ")),
+ {ok, {404, Body1}} = httpc:request(get, {URL, []},
+ [{version, "HTTP/1.0"}], [{full_result, false}]),
+ HTMLEncodedPath = http_util:html_encode(Path),
+ HTMLEncodedPath = find_URL_path(string:tokens(Body1, " ")),
inets:stop(httpd, Pid).
find_URL_path([]) ->
--
cgit v1.2.3
From 73f261d2f44a58fda92e3d6e035051c11c3e4521 Mon Sep 17 00:00:00 2001
From: Bernard Duggan
Date: Wed, 23 Feb 2011 15:55:37 +1100
Subject: Modify mod_esi:deliver/2 to accept binary data
This change allows for more efficient delivery of large amounts of
data through the mod_esi interface when the handling process has that
data in binary format. It avoids the need to convert to list and the
extra memory involved in passing that list between processes.
---
lib/inets/doc/src/mod_esi.xml | 6 ++++--
lib/inets/src/http_server/mod_esi.erl | 4 ++++
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/lib/inets/doc/src/mod_esi.xml b/lib/inets/doc/src/mod_esi.xml
index 3c473d3f94..e063088eb4 100644
--- a/lib/inets/doc/src/mod_esi.xml
+++ b/lib/inets/doc/src/mod_esi.xml
@@ -41,7 +41,7 @@
Sends Data back to client.
SessionID = term()
- Data = string() | io_list()
+ Data = string() | io_list() | binary()
Reason = term()
@@ -54,7 +54,9 @@
Note
that if any HTTP-header fields should be added by the
script they must be in the first call to deliver/2 and the
- data in the call must be a string. Do not
+ data in the call must be a string. Calls after the headers
+ are complete may contain binary data to reduce copying
+ overhead. Do not
assume anything about the data type of SessionID, the
SessionID must be the value given as input to the esi
call back function that you implemented.
diff --git a/lib/inets/src/http_server/mod_esi.erl b/lib/inets/src/http_server/mod_esi.erl
index 929185a67a..b85c479693 100644
--- a/lib/inets/src/http_server/mod_esi.erl
+++ b/lib/inets/src/http_server/mod_esi.erl
@@ -452,6 +452,10 @@ handle_body(Pid, ModData, Body, Timeout, Size, IsDisableChunkedSend) ->
?hdrt("handle_body - send chunk", [{timeout, Timeout}, {size, Size}]),
httpd_response:send_chunk(ModData, Body, IsDisableChunkedSend),
receive
+ {esi_data, Data} when is_binary(Data) ->
+ ?hdrt("handle_body - received binary data (esi)", []),
+ handle_body(Pid, ModData, Data, Timeout, Size + byte_size(Data),
+ IsDisableChunkedSend);
{esi_data, Data} ->
?hdrt("handle_body - received data (esi)", []),
handle_body(Pid, ModData, Data, Timeout, Size + length(Data),
--
cgit v1.2.3
From db29f9ede14ff5b8d747230fcad8ffa1b157f1e1 Mon Sep 17 00:00:00 2001
From: Micael Karlberg
Date: Mon, 7 Mar 2011 14:52:30 +0100
Subject: Adding missing "send loop" for raw sending. Also fixed some of the
documentation (types).
---
lib/inets/doc/src/httpc.xml | 52 ++++---
lib/inets/doc/src/notes.xml | 85 +++++++----
lib/inets/src/http_client/httpc.erl | 85 +++++++----
lib/inets/src/http_client/httpc_handler.erl | 18 +++
lib/inets/src/http_client/httpc_request.erl | 52 ++++---
lib/inets/test/httpc_SUITE.erl | 229 ++++++++++------------------
6 files changed, 269 insertions(+), 252 deletions(-)
diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml
index 6dcf2d6d17..12f4fa535e 100644
--- a/lib/inets/doc/src/httpc.xml
+++ b/lib/inets/doc/src/httpc.xml
@@ -76,25 +76,29 @@ socket_opt() = See the Options used by gen_tcp(3) and
For more information about HTTP see rfc 2616
send_fun_result(), acc()} |
- {chunkify, fun(acc()) -> send_fun_result(), acc()}
-send_fun_result() = eof | {ok, iolist(), acc()}
-acc() = term()
-filename() = string()
+method() = head | get | put | post | trace | options | delete
+request() = {url(), headers()} |
+ {url(), headers(), content_type(), body()}
+url() = string() - Syntax according to the URI definition in rfc 2396, ex: "http://www.erlang.org"
+status_line() = {http_version(), status_code(), reason_phrase()}
+http_version() = string() ex: "HTTP/1.1"
+status_code() = integer()
+reason_phrase() = string()
+content_type() = string()
+headers() = [header()]
+header() = {field(), value()}
+field() = string()
+value() = string()
+body() = string() |
+ binary() |
+ {fun(accumulator()) -> body_processing_result(),
+ accumulator()} |
+ {chunkify,
+ fun(accumulator()) -> body_processing_result(),
+ accumulator()}
+body_processing_result() = eof | {ok, iolist(), accumulator()}
+accumulator() = term()
+filename() = string()
]]>
@@ -146,8 +150,9 @@ ssl_options() = {verify, code()} |
Sends a get HTTP-request
Url = url()
- Result = {status_line(), headers(), body()} |
- {status_code(), body()} | request_id()
+ Result = {status_line(), headers(), Body} |
+ {status_code(), Body} | request_id()
+ Body = string() | binary()
Profile = profile()
Reason = term()
@@ -195,8 +200,9 @@ ssl_options() = {verify, code()} |
Function = atom()
Args = list()
body_format() = string | binary
- Result = {status_line(), headers(), body()} |
- {status_code(), body()} | request_id()
+ Result = {status_line(), headers(), Body} |
+ {status_code(), Body} | request_id()
+ Body = string() | binary()
Profile = profile()
Reason = {connect_failed, term()} |
{send_failed, term()} | term()
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 11b0af4310..8c0d683a90 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -1,4 +1,4 @@
-
+
@@ -32,50 +32,80 @@
notes.xml
- Inets 5.5.1
+ Inets 5.6
- Fixed Bugs and Malfunctions
+ Improvements and New Features
+
-
-
Fix format_man_pages so it handles all man sections
- and remove warnings/errors in various man pages.
-
- Own Id: OTP-8600
+ [httpc] Add support for upload body streaming (PUT and POST).
+ For more info,
+ see the definition of the Body argument of the
+ request/4,5
+ function.
+ Filipe David Manana
+ Own Id: OTP-9094
+
+
+
+ Fixed Bugs and Malfunctions
+ -
+
+
+
+
+
+ Inets 5.5.1
+
Improvements and New Features
-
-
- Miscellaneous inet6 related problems.
-
- Own Id: OTP-8927
+ Miscellaneous inet6 related problems.
+ Own Id: OTP-8927
-
-
- Updated http-server to make sure URLs in error-messages
- are URL-encoded. Added support in http-client to use
- URL-encoding. Also added the missing include directory
- for the inets application.
-
- Own Id: OTP-8940 Aux Id: seq11735
+ Updated http-server to make sure URLs in error-messages
+ are URL-encoded. Added support in http-client to use
+ URL-encoding. Also added the missing include directory
+ for the inets application.
+ Own Id: OTP-8940, Aux Id: seq11735
-
+ Fixed Bugs and Malfunctions
+
+ -
+
Fix format_man_pages so it handles all man sections
+ and remove warnings/errors in various man pages.
+ Own Id: OTP-8600
+
+ -
+
[httpc] Pipelined and queued requests not processed when
+ connection closed remotelly.
+ Own Id: OTP-8906
+
+
+
+
+
+
-Inets 5.5
+ Inets 5.5
Fixed Bugs and Malfunctions
@@ -120,9 +150,10 @@
-
+
+
-Inets 5.4
+ Inets 5.4
Improvements and New Features
+
+
+ -
+
[ftp] Added (type) spec for all exported functions.
+ Own Id: OTP-9114 Aux Id: seq11799
+
+
+
+
+
+ Fixed Bugs and Malfunctions
+ -
+
+
+
+
+
+
+
Inets 5.5.2
Improvements and New Features
diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl
index 5ad74851c8..fe6cb0c191 100644
--- a/lib/inets/src/ftp/ftp.erl
+++ b/lib/inets/src/ftp/ftp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -92,6 +92,12 @@
}).
+-type shortage_reason() :: 'etnospc' | 'epnospc'.
+-type restriction_reason() :: 'epath' | 'efnamena' | 'elogin' | 'enotbinary'.
+-type common_reason() :: 'econn' | 'eclosed' | term().
+-type file_write_error_reason() :: term(). % See file:write for more info
+
+
%%%=========================================================================
%%% API - CLIENT FUNCTIONS
%%%=========================================================================
@@ -106,6 +112,9 @@
%% Description: Start an ftp client and connect to a host.
%%--------------------------------------------------------------------------
+-spec open(Host :: string() | inet:ip_address()) ->
+ {'ok', Pid :: pid()} | {'error', Reason :: 'ehost' | term()}.
+
%%
open({option_list, Options}) when is_list(Options) ->
try
@@ -126,6 +135,9 @@ open({option_list, Options}) when is_list(Options) ->
open(Host) ->
open(Host, []).
+-spec open(Host :: string() | inet:ip_address(), Opts :: list()) ->
+ {'ok', Pid :: pid()} | {'error', Reason :: 'ehost' | term()}.
+
%%
open(Host, Port) when is_integer(Port) ->
open(Host, [{port, Port}]);
@@ -161,12 +173,24 @@ open(Host, Opts) when is_list(Opts) ->
%%
%% Description: Login with or without a supplied account name.
%%--------------------------------------------------------------------------
+-spec user(Pid :: pid(),
+ User :: string(),
+ Pass :: string()) ->
+ 'ok' | {'error', Reason :: 'euser' | common_reason()}.
+
user(Pid, User, Pass) ->
call(Pid, {user, User, Pass}, atom).
+-spec user(Pid :: pid(),
+ User :: string(),
+ Pass :: string(),
+ Acc :: string()) ->
+ 'ok' | {'error', Reason :: 'euser' | common_reason()}.
+
user(Pid, User, Pass, Acc) ->
call(Pid, {user, User, Pass, Acc}, atom).
+
%%--------------------------------------------------------------------------
%% account(Pid, Acc) -> ok | {error, eacct}
%% Pid = pid()
@@ -174,9 +198,14 @@ user(Pid, User, Pass, Acc) ->
%%
%% Description: Set a user Account.
%%--------------------------------------------------------------------------
+
+-spec account(Pid :: pid(), Acc :: string()) ->
+ 'ok' | {'error', Reason :: 'eacct' | common_reason()}.
+
account(Pid, Acc) ->
call(Pid, {account, Acc}, atom).
+
%%--------------------------------------------------------------------------
%% pwd(Pid) -> {ok, Dir} | {error, elogin} | {error, econn}
%% Pid = pid()
@@ -184,19 +213,30 @@ account(Pid, Acc) ->
%%
%% Description: Get the current working directory at remote server.
%%--------------------------------------------------------------------------
+
+-spec pwd(Pid :: pid()) ->
+ {'ok', Dir :: string()} |
+ {'error', Reason :: restriction_reason() | common_reason()}.
+
pwd(Pid) ->
call(Pid, pwd, ctrl).
+
%%--------------------------------------------------------------------------
-%% lpwd(Pid) -> {ok, Dir} | {error, elogin}
+%% lpwd(Pid) -> {ok, Dir}
%% Pid = pid()
%% Dir = string()
%%
%% Description: Get the current working directory at local server.
%%--------------------------------------------------------------------------
+
+-spec lpwd(Pid :: pid()) ->
+ {'ok', Dir :: string()}.
+
lpwd(Pid) ->
call(Pid, lpwd, string).
+
%%--------------------------------------------------------------------------
%% cd(Pid, Dir) -> ok | {error, epath} | {error, elogin} | {error, econn}
%% Pid = pid()
@@ -204,9 +244,14 @@ lpwd(Pid) ->
%%
%% Description: Change current working directory at remote server.
%%--------------------------------------------------------------------------
+
+-spec cd(Pid :: pid(), Dir :: string()) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
cd(Pid, Dir) ->
call(Pid, {cd, Dir}, atom).
+
%%--------------------------------------------------------------------------
%% lcd(Pid, Dir) -> ok | {error, epath}
%% Pid = pid()
@@ -214,9 +259,14 @@ cd(Pid, Dir) ->
%%
%% Description: Change current working directory for the local client.
%%--------------------------------------------------------------------------
+
+-spec lcd(Pid :: pid(), Dir :: string()) ->
+ 'ok' | {'error', Reason :: restriction_reason()}.
+
lcd(Pid, Dir) ->
call(Pid, {lcd, Dir}, string).
+
%%--------------------------------------------------------------------------
%% ls(Pid) -> Result
%% ls(Pid, ) -> Result
@@ -229,11 +279,22 @@ lcd(Pid, Dir) ->
%%
%% Description: Returns a list of files in long format.
%%--------------------------------------------------------------------------
+
+-spec ls(Pid :: pid()) ->
+ {'ok', Listing :: string()} |
+ {'error', Reason :: restriction_reason() | common_reason()}.
+
ls(Pid) ->
ls(Pid, "").
+
+-spec ls(Pid :: pid(), Dir :: string()) ->
+ {'ok', Listing :: string()} |
+ {'error', Reason :: restriction_reason() | common_reason()}.
+
ls(Pid, Dir) ->
call(Pid, {dir, long, Dir}, string).
+
%%--------------------------------------------------------------------------
%% nlist(Pid) -> Result
%% nlist(Pid, Pathname) -> Result
@@ -246,21 +307,37 @@ ls(Pid, Dir) ->
%%
%% Description: Returns a list of files in short format
%%--------------------------------------------------------------------------
+
+-spec nlist(Pid :: pid()) ->
+ {'ok', Listing :: string()} |
+ {'error', Reason :: restriction_reason() | common_reason()}.
+
nlist(Pid) ->
nlist(Pid, "").
+
+-spec nlist(Pid :: pid(), Pathname :: string()) ->
+ {'ok', Listing :: string()} |
+ {'error', Reason :: restriction_reason() | common_reason()}.
+
nlist(Pid, Dir) ->
call(Pid, {dir, short, Dir}, string).
+
%%--------------------------------------------------------------------------
-%% rename(Pid, CurrFile, NewFile) -> ok | {error, epath} | {error, elogin}
-%% | {error, econn}
+%% rename(Pid, Old, New) -> ok | {error, epath} | {error, elogin}
+%% | {error, econn}
%% Pid = pid()
%% CurrFile = NewFile = string()
%%
%% Description: Rename a file at remote server.
%%--------------------------------------------------------------------------
-rename(Pid, CurrFile, NewFile) ->
- call(Pid, {rename, CurrFile, NewFile}, string).
+
+-spec rename(Pid :: pid(), Old :: string(), New :: string()) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
+rename(Pid, Old, New) ->
+ call(Pid, {rename, Old, New}, string).
+
%%--------------------------------------------------------------------------
%% delete(Pid, File) -> ok | {error, epath} | {error, elogin} |
@@ -270,9 +347,14 @@ rename(Pid, CurrFile, NewFile) ->
%%
%% Description: Remove file at remote server.
%%--------------------------------------------------------------------------
+
+-spec delete(Pid :: pid(), File :: string()) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
delete(Pid, File) ->
call(Pid, {delete, File}, string).
+
%%--------------------------------------------------------------------------
%% mkdir(Pid, Dir) -> ok | {error, epath} | {error, elogin} | {error, econn}
%% Pid = pid(),
@@ -280,9 +362,14 @@ delete(Pid, File) ->
%%
%% Description: Make directory at remote server.
%%--------------------------------------------------------------------------
+
+-spec mkdir(Pid :: pid(), Dir :: string()) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
mkdir(Pid, Dir) ->
call(Pid, {mkdir, Dir}, atom).
+
%%--------------------------------------------------------------------------
%% rmdir(Pid, Dir) -> ok | {error, epath} | {error, elogin} | {error, econn}
%% Pid = pid(),
@@ -290,9 +377,14 @@ mkdir(Pid, Dir) ->
%%
%% Description: Remove directory at remote server.
%%--------------------------------------------------------------------------
+
+-spec rmdir(Pid :: pid(), Dir :: string()) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
rmdir(Pid, Dir) ->
call(Pid, {rmdir, Dir}, atom).
+
%%--------------------------------------------------------------------------
%% type(Pid, Type) -> ok | {error, etype} | {error, elogin} | {error, econn}
%% Pid = pid()
@@ -300,23 +392,41 @@ rmdir(Pid, Dir) ->
%%
%% Description: Set transfer type.
%%--------------------------------------------------------------------------
+
+-spec type(Pid :: pid(), Type :: ascii | binary) ->
+ 'ok' |
+ {'error', Reason :: 'etype' | restriction_reason() | common_reason()}.
+
type(Pid, Type) ->
call(Pid, {type, Type}, atom).
+
%%--------------------------------------------------------------------------
-%% recv(Pid, RemoteFileName ) -> ok | {error, epath} |
+%% recv(Pid, RemoteFileName [, LocalFileName]) -> ok | {error, epath} |
%% {error, elogin} | {error, econn}
%% Pid = pid()
%% RemoteFileName = LocalFileName = string()
%%
%% Description: Transfer file from remote server.
%%--------------------------------------------------------------------------
+
+-spec recv(Pid :: pid(), RemoteFileName :: string()) ->
+ 'ok' | {'error', Reason :: restriction_reason() |
+ common_reason() |
+ file_write_error_reason()}.
+
recv(Pid, RemotFileName) ->
recv(Pid, RemotFileName, RemotFileName).
+-spec recv(Pid :: pid(),
+ RemoteFileName :: string(),
+ LocalFileName :: string()) ->
+ 'ok' | {'error', Reason :: term()}.
+
recv(Pid, RemotFileName, LocalFileName) ->
call(Pid, {recv, RemotFileName, LocalFileName}, atom).
+
%%--------------------------------------------------------------------------
%% recv_bin(Pid, RemoteFile) -> {ok, Bin} | {error, epath} | {error, elogin}
%% | {error, econn}
@@ -326,9 +436,16 @@ recv(Pid, RemotFileName, LocalFileName) ->
%%
%% Description: Transfer file from remote server into binary.
%%--------------------------------------------------------------------------
+
+-spec recv_bin(Pid :: pid(),
+ RemoteFile :: string()) ->
+ {'ok', Bin :: binary()} |
+ {'error', Reason :: restriction_reason() | common_reason()}.
+
recv_bin(Pid, RemoteFile) ->
call(Pid, {recv_bin, RemoteFile}, bin).
+
%%--------------------------------------------------------------------------
%% recv_chunk_start(Pid, RemoteFile) -> ok | {error, elogin} | {error, epath}
%% | {error, econn}
@@ -337,9 +454,15 @@ recv_bin(Pid, RemoteFile) ->
%%
%% Description: Start receive of chunks of remote file.
%%--------------------------------------------------------------------------
+
+-spec recv_chunk_start(Pid :: pid(),
+ RemoteFile :: string()) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
recv_chunk_start(Pid, RemoteFile) ->
call(Pid, {recv_chunk_start, RemoteFile}, atom).
+
%%--------------------------------------------------------------------------
%% recv_chunk(Pid, RemoteFile) -> ok | {ok, Bin} | {error, Reason}
%% Pid = pid()
@@ -347,24 +470,47 @@ recv_chunk_start(Pid, RemoteFile) ->
%%
%% Description: Transfer file from remote server into binary in chunks
%%--------------------------------------------------------------------------
+
+-spec recv_chunk(Pid :: pid()) ->
+ 'ok' |
+ {'ok', Bin :: binary()} |
+ {'error', Reason :: restriction_reason() | common_reason()}.
+
recv_chunk(Pid) ->
call(Pid, recv_chunk, atom).
+
%%--------------------------------------------------------------------------
-%% send(Pid, LocalFileName ) -> ok | {error, epath}
-%% | {error, elogin}
-%% | {error, econn}
+%% send(Pid, LocalFileName [, RemotFileName]) -> ok | {error, epath}
+%% | {error, elogin}
+%% | {error, econn}
%% Pid = pid()
%% LocalFileName = RemotFileName = string()
%%
%% Description: Transfer file to remote server.
%%--------------------------------------------------------------------------
+
+-spec send(Pid :: pid(), LocalFileName :: string()) ->
+ 'ok' |
+ {'error', Reason :: restriction_reason() |
+ common_reason() |
+ shortage_reason()}.
+
send(Pid, LocalFileName) ->
send(Pid, LocalFileName, LocalFileName).
+-spec send(Pid :: pid(),
+ LocalFileName :: string(),
+ RemoteFileName :: string()) ->
+ 'ok' |
+ {'error', Reason :: restriction_reason() |
+ common_reason() |
+ shortage_reason()}.
+
send(Pid, LocalFileName, RemotFileName) ->
call(Pid, {send, LocalFileName, RemotFileName}, atom).
+
%%--------------------------------------------------------------------------
%% send_bin(Pid, Bin, RemoteFile) -> ok | {error, epath} | {error, elogin}
%% | {error, enotbinary} | {error, econn}
@@ -374,11 +520,19 @@ send(Pid, LocalFileName, RemotFileName) ->
%%
%% Description: Transfer a binary to a remote file.
%%--------------------------------------------------------------------------
+
+-spec send_bin(Pid :: pid(), Bin :: binary(), RemoteFile :: string()) ->
+ 'ok' |
+ {'error', Reason :: restriction_reason() |
+ common_reason() |
+ shortage_reason()}.
+
send_bin(Pid, Bin, RemoteFile) when is_binary(Bin) ->
call(Pid, {send_bin, Bin, RemoteFile}, atom);
send_bin(_Pid, _Bin, _RemoteFile) ->
{error, enotbinary}.
+
%%--------------------------------------------------------------------------
%% send_chunk_start(Pid, RemoteFile) -> ok | {error, elogin} | {error, epath}
%% | {error, econn}
@@ -387,9 +541,14 @@ send_bin(_Pid, _Bin, _RemoteFile) ->
%%
%% Description: Start transfer of chunks to remote file.
%%--------------------------------------------------------------------------
+
+-spec send_chunk_start(Pid :: pid(), RemoteFile :: string()) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
send_chunk_start(Pid, RemoteFile) ->
call(Pid, {send_chunk_start, RemoteFile}, atom).
+
%%--------------------------------------------------------------------------
%% append_chunk_start(Pid, RemoteFile) -> ok | {error, elogin} |
%% {error, epath} | {error, econn}
@@ -398,9 +557,14 @@ send_chunk_start(Pid, RemoteFile) ->
%%
%% Description: Start append chunks of data to remote file.
%%--------------------------------------------------------------------------
+
+-spec append_chunk_start(Pid :: pid(), RemoteFile :: string()) ->
+ 'ok' | {'error', Reason :: term()}.
+
append_chunk_start(Pid, RemoteFile) ->
call(Pid, {append_chunk_start, RemoteFile}, atom).
+
%%--------------------------------------------------------------------------
%% send_chunk(Pid, Bin) -> ok | {error, elogin} | {error, enotbinary}
%% | {error, echunk} | {error, econn}
@@ -409,11 +573,19 @@ append_chunk_start(Pid, RemoteFile) ->
%%
%% Purpose: Send chunk to remote file.
%%--------------------------------------------------------------------------
+
+-spec send_chunk(Pid :: pid(), Bin :: binary()) ->
+ 'ok' |
+ {'error', Reason :: 'echunk' |
+ restriction_reason() |
+ common_reason()}.
+
send_chunk(Pid, Bin) when is_binary(Bin) ->
call(Pid, {transfer_chunk, Bin}, atom);
send_chunk(_Pid, _Bin) ->
{error, enotbinary}.
+
%%--------------------------------------------------------------------------
%% append_chunk(Pid, Bin) -> ok | {error, elogin} | {error, enotbinary}
%% | {error, echunk} | {error, econn}
@@ -422,11 +594,19 @@ send_chunk(_Pid, _Bin) ->
%%
%% Description: Append chunk to remote file.
%%--------------------------------------------------------------------------
+
+-spec append_chunk(Pid :: pid(), Bin :: binary()) ->
+ 'ok' |
+ {'error', Reason :: 'echunk' |
+ restriction_reason() |
+ common_reason()}.
+
append_chunk(Pid, Bin) when is_binary(Bin) ->
call(Pid, {transfer_chunk, Bin}, atom);
append_chunk(_Pid, _Bin) ->
{error, enotbinary}.
+
%%--------------------------------------------------------------------------
%% send_chunk_end(Pid) -> ok | {error, elogin} | {error, echunk}
%% | {error, econn}
@@ -434,9 +614,17 @@ append_chunk(_Pid, _Bin) ->
%%
%% Description: End sending of chunks to remote file.
%%--------------------------------------------------------------------------
+
+-spec send_chunk_end(Pid :: pid()) ->
+ 'ok' |
+ {'error', Reason :: restriction_reason() |
+ common_reason() |
+ shortage_reason()}.
+
send_chunk_end(Pid) ->
call(Pid, chunk_end, atom).
+
%%--------------------------------------------------------------------------
%% append_chunk_end(Pid) -> ok | {error, elogin} | {error, echunk}
%% | {error, econn}
@@ -444,23 +632,47 @@ send_chunk_end(Pid) ->
%%
%% Description: End appending of chunks to remote file.
%%--------------------------------------------------------------------------
+
+-spec append_chunk_end(Pid :: pid()) ->
+ 'ok' |
+ {'error', Reason :: restriction_reason() |
+ common_reason() |
+ shortage_reason()}.
+
append_chunk_end(Pid) ->
call(Pid, chunk_end, atom).
+
%%--------------------------------------------------------------------------
-%% append(Pid, LocalFileName, RemotFileName) -> ok | {error, epath}
-%% | {error, elogin} | {error, econn}
+%% append(Pid, LocalFileName [, RemotFileName]) -> ok | {error, epath}
+%% | {error, elogin}
+%% | {error, econn}
%% Pid = pid()
%% LocalFileName = RemotFileName = string()
%%
%% Description: Append the local file to the remote file
%%--------------------------------------------------------------------------
+
+-spec append(Pid :: pid(), LocalFileName :: string()) ->
+ 'ok' |
+ {'error', Reason :: 'epath' |
+ 'elogin' |
+ 'etnospc' |
+ 'epnospc' |
+ 'efnamena' | common_reason()}.
+
append(Pid, LocalFileName) ->
append(Pid, LocalFileName, LocalFileName).
+-spec append(Pid :: pid(),
+ LocalFileName :: string(),
+ RemoteFileName :: string()) ->
+ 'ok' | {'error', Reason :: term()}.
+
append(Pid, LocalFileName, RemotFileName) ->
call(Pid, {append, LocalFileName, RemotFileName}, atom).
+
%%--------------------------------------------------------------------------
%% append_bin(Pid, Bin, RemoteFile) -> ok | {error, epath} | {error, elogin}
%% | {error, enotbinary} | {error, econn}
@@ -470,27 +682,44 @@ append(Pid, LocalFileName, RemotFileName) ->
%%
%% Purpose: Append a binary to a remote file.
%%--------------------------------------------------------------------------
+
+-spec append_bin(Pid :: pid(),
+ Bin :: binary(),
+ RemoteFile :: string()) ->
+ 'ok' |
+ {'error', Reason :: restriction_reason() |
+ common_reason() |
+ shortage_reason()}.
+
append_bin(Pid, Bin, RemoteFile) when is_binary(Bin) ->
call(Pid, {append_bin, Bin, RemoteFile}, atom);
append_bin(_Pid, _Bin, _RemoteFile) ->
{error, enotbinary}.
+
%%--------------------------------------------------------------------------
-%% quote(Pid, Cmd) -> ok
+%% quote(Pid, Cmd) -> list()
%% Pid = pid()
%% Cmd = string()
%%
%% Description: Send arbitrary ftp command.
%%--------------------------------------------------------------------------
+
+-spec quote(Pid :: pid(), Cmd :: string()) -> list().
+
quote(Pid, Cmd) when is_list(Cmd) ->
call(Pid, {quote, Cmd}, atom).
+
%%--------------------------------------------------------------------------
%% close(Pid) -> ok
%% Pid = pid()
%%
%% Description: End the ftp session.
%%--------------------------------------------------------------------------
+
+-spec close(Pid :: pid()) -> 'ok'.
+
close(Pid) ->
cast(Pid, close),
ok.
@@ -502,9 +731,13 @@ close(Pid) ->
%%
%% Description: Return diagnostics.
%%--------------------------------------------------------------------------
+
+-spec formaterror(Tag :: term()) -> string().
+
formaterror(Tag) ->
ftp_response:error_string(Tag).
+
info(Pid) ->
call(Pid, info, list).
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index 07da8ca961..6f32a31c1c 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -18,8 +18,14 @@
{"%VSN%",
[
+ {"5.5.2",
+ [
+ {load_module, ftp, soft_purge, soft_purge, []}
+ ]
+ },
{"5.5.1",
[
+ {load_module, ftp, soft_purge, soft_purge, []},
{load_module, http_chunk, soft_purge, soft_purge, []}
]
},
@@ -35,8 +41,14 @@
}
],
[
+ {"5.5.2",
+ [
+ {load_module, ftp, soft_purge, soft_purge, []}
+ ]
+ },
{"5.5.1",
[
+ {load_module, ftp, soft_purge, soft_purge, []},
{load_module, http_chunk, soft_purge, soft_purge, []}
]
},
diff --git a/lib/inets/test/ftp_SUITE.erl b/lib/inets/test/ftp_SUITE.erl
index 7059bb12cf..17e5f6777e 100644
--- a/lib/inets/test/ftp_SUITE.erl
+++ b/lib/inets/test/ftp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -57,35 +57,42 @@
%% Description: Returns documentation/test cases in this test suite
%% or a skip tuple if the platform is not supported.
%%--------------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() -> [{ct_hooks, [ts_install_cth]}].
all() ->
- [{group, solaris8_test}, {group, solaris9_test},
- {group, solaris10_test}, {group, linux_x86_test},
- {group, linux_ppc_test}, {group, macosx_x86_test},
- {group, macosx_ppc_test}, {group, openbsd_test},
- {group, freebsd_test}, {group, netbsd_test},
+ [
+ {group, solaris8_test},
+ {group, solaris9_test},
+ {group, solaris10_test},
+ {group, linux_x86_test},
+ {group, linux_ppc_test},
+ {group, macosx_x86_test},
+ {group, macosx_ppc_test},
+ {group, openbsd_test},
+ {group, freebsd_test},
+ {group, netbsd_test},
{group, windows_xp_test},
{group, windows_2003_server_test},
- {group, ticket_tests}].
+ {group, ticket_tests}
+ ].
groups() ->
- [{solaris8_test, [], [{ftp_solaris8_sparc_test, all}]},
- {solaris9_test, [], [{ftp_solaris9_sparc_test, all}]},
- {solaris10_test, [],
- [{ftp_solaris10_sparc_test, all},
- {ftp_solaris10_x86_test, all}]},
- {linux_x86_test, [], [{ftp_linux_x86_test, all}]},
- {linux_ppc_test, [], [{ftp_linux_ppc_test, all}]},
- {macosx_x86_test, [], [{ftp_macosx_x86_test, all}]},
- {macosx_ppc_test, [], [{ftp_macosx_ppc_test, all}]},
- {openbsd_test, [], [{ftp_openbsd_x86_test, all}]},
- {freebsd_test, [], [{ftp_freebsd_x86_test, all}]},
- {netbsd_test, [], [{ftp_netbsd_x86_test, all}]},
- {windows_xp_test, [], [{ftp_windows_xp_test, all}]},
- {windows_2003_server_test, [],
- [{ftp_windows_2003_server_test, all}]},
- {ticket_tests, [], [{ftp_ticket_test, all}]}].
+ [
+ {solaris8_test, [], [{ftp_solaris8_sparc_test, all}]},
+ {solaris9_test, [], [{ftp_solaris9_sparc_test, all}]},
+ {solaris10_test, [], [{ftp_solaris10_sparc_test, all},
+ {ftp_solaris10_x86_test, all}]},
+ {linux_x86_test, [], [{ftp_linux_x86_test, all}]},
+ {linux_ppc_test, [], [{ftp_linux_ppc_test, all}]},
+ {macosx_x86_test, [], [{ftp_macosx_x86_test, all}]},
+ {macosx_ppc_test, [], [{ftp_macosx_ppc_test, all}]},
+ {openbsd_test, [], [{ftp_openbsd_x86_test, all}]},
+ {freebsd_test, [], [{ftp_freebsd_x86_test, all}]},
+ {netbsd_test, [], [{ftp_netbsd_x86_test, all}]},
+ {windows_xp_test, [], [{ftp_windows_xp_test, all}]},
+ {windows_2003_server_test, [], [{ftp_windows_2003_server_test, all}]},
+ {ticket_tests, [], [{ftp_ticket_test, all}]}
+ ].
init_per_group(_GroupName, Config) ->
Config.
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index b1de3fef43..c0e25a30e3 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -18,7 +18,7 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 5.5.2
+INETS_VSN = 5.6
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
--
cgit v1.2.3
From 52b0134e8f7b871051af9be6cb7354553a0f72cd Mon Sep 17 00:00:00 2001
From: Micael Karlberg
Date: Thu, 10 Mar 2011 11:20:16 +0100
Subject: Added proper release notes, appup and version.
---
lib/inets/doc/src/mod_esi.xml | 29 +++++++++++++-----------
lib/inets/doc/src/notes.xml | 39 +++++++++++++++++++++++++++++++++
lib/inets/src/inets_app/inets.appup.src | 12 +++++++++-
lib/inets/vsn.mk | 2 +-
4 files changed, 67 insertions(+), 15 deletions(-)
diff --git a/lib/inets/doc/src/mod_esi.xml b/lib/inets/doc/src/mod_esi.xml
index e063088eb4..7b1e93e313 100644
--- a/lib/inets/doc/src/mod_esi.xml
+++ b/lib/inets/doc/src/mod_esi.xml
@@ -1,10 +1,10 @@
-
+
- 19972010
+ 19972011
Ericsson AB. All Rights Reserved.
@@ -32,9 +32,12 @@
Erlang Server Interface
This module defines the API - Erlang Server Interface (ESI).
- Which is a more efficient way of writing erlang scripts
- for your Inets web server than writing them as common CGI scripts.
+ Which is a more efficient way of writing erlang scripts
+ for your Inets web server than writing them as common CGI scripts.
+
+
+
deliver(SessionID, Data) -> ok | {error, Reason}
@@ -51,15 +54,15 @@
parts of the content to the user.
Sends data from a Erl Scheme script back to the client.
- Note
- that if any HTTP-header fields should be added by the
- script they must be in the first call to deliver/2 and the
- data in the call must be a string. Calls after the headers
- are complete may contain binary data to reduce copying
- overhead. Do not
- assume anything about the data type of SessionID, the
- SessionID must be the value given as input to the esi
- call back function that you implemented.
+
+ Note that if any HTTP-header fields should be added by the
+ script they must be in the first call to deliver/2 and the
+ data in the call must be a string. Calls after the headers
+ are complete may contain binary data to reduce copying
+ overhead. Do not assume anything about the data type of
+ SessionID, the SessionID must be the value given as input to
+ the esi call back function that you implemented.
+
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 5da9d98002..8e1acba9b8 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -32,6 +32,45 @@
notes.xml
+ Inets 5.6
+
+ Improvements and New Features
+
+
+
+ -
+
[httpd]
+ mod_esi:deliver/2
+ made to accept binary data.
+ Own Id: OTP-9123
+
+
+
+
+
+ Fixed Bugs and Malfunctions
+ -
+
+
+
+
+
+
Inets 5.5.2
Improvements and New Features
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index 07da8ca961..b75277706f 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -18,6 +18,11 @@
{"%VSN%",
[
+ {"5.5.2",
+ [
+ {load_module, mod_esi, soft_purge, soft_purge, []}
+ ]
+ },
{"5.5.1",
[
{load_module, http_chunk, soft_purge, soft_purge, []}
@@ -34,7 +39,12 @@
]
}
],
- [
+ [
+ {"5.5.2",
+ [
+ {load_module, mod_esi, soft_purge, soft_purge, []}
+ ]
+ },
{"5.5.1",
[
{load_module, http_chunk, soft_purge, soft_purge, []}
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index b1de3fef43..c0e25a30e3 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -18,7 +18,7 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 5.5.2
+INETS_VSN = 5.6
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
--
cgit v1.2.3
From 06b742fd9fcdbff2cec092565d920462335cfbc0 Mon Sep 17 00:00:00 2001
From: Micael Karlberg
Date: Thu, 10 Mar 2011 11:24:15 +0100
Subject: Removed email address.
---
lib/inets/test/httpd_mod.erl | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/inets/test/httpd_mod.erl b/lib/inets/test/httpd_mod.erl
index f2c1fd6a65..1754cec7bc 100644
--- a/lib/inets/test/httpd_mod.erl
+++ b/lib/inets/test/httpd_mod.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -19,7 +19,6 @@
%%
-module(httpd_mod).
--author('ingela@erix.ericsson.se').
-include("test_server.hrl").
-include("test_server_line.hrl").
@@ -815,6 +814,8 @@ esi(Type, Port, Host, Node) ->
[{statuscode, 302},
{version, "HTTP/1.0"}]),
ok.
+
+
%%--------------------------------------------------------------------
get(Type, Port, Host, Node) ->
ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
--
cgit v1.2.3
From 0422eb9016dd7bea2dff4004895ed45815ef0f48 Mon Sep 17 00:00:00 2001
From: Micael Karlberg
Date: Thu, 10 Mar 2011 16:15:35 +0100
Subject: Added proper release notes, appup and version.
---
lib/inets/doc/src/notes.xml | 41 +++++++++++++++++++++++++++++++++
lib/inets/src/inets_app/inets.appup.src | 13 ++++++++++-
lib/inets/vsn.mk | 2 +-
3 files changed, 54 insertions(+), 2 deletions(-)
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 5da9d98002..5dbe761988 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -32,6 +32,47 @@
notes.xml
+ Inets 5.6
+
+ Improvements and New Features
+
+
+
+ -
+
[httpd] Prevent XSS in error pages.
+ Prevent user controlled input from being interpreted
+ as HTML in error pages by encoding the reserved HTML
+ characters.
+ Michael Santos
+ Own Id: OTP-9124
+
+
+
+
+
+ Fixed Bugs and Malfunctions
+ -
+
+
+
+
+
+
Inets 5.5.2
Improvements and New Features
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index 07da8ca961..7e3785e240 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -18,6 +18,12 @@
{"%VSN%",
[
+ {"5.5.2",
+ [
+ {load_module, http_util, soft_purge, soft_purge, []},
+ {load_module, httpd_util, soft_purge, soft_purge, [http_util]}
+ ]
+ },
{"5.5.1",
[
{load_module, http_chunk, soft_purge, soft_purge, []}
@@ -34,7 +40,12 @@
]
}
],
- [
+ [
+ {"5.5.2",
+ [
+ {load_module, http_util, soft_purge, soft_purge, []},
+ {load_module, httpd_util, soft_purge, soft_purge, [http_util]}
+ ]
{"5.5.1",
[
{load_module, http_chunk, soft_purge, soft_purge, []}
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index b1de3fef43..c0e25a30e3 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -18,7 +18,7 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 5.5.2
+INETS_VSN = 5.6
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
--
cgit v1.2.3
From a5d14f14e04ca7ca5fd34a7811cefbccdd024ce4 Mon Sep 17 00:00:00 2001
From: Micael Karlberg
Date: Thu, 10 Mar 2011 16:19:20 +0100
Subject: Add original auther (Bernard Duggan) in release notes.
---
lib/inets/doc/src/notes.xml | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 8e1acba9b8..50dbb7d3da 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -44,6 +44,7 @@
[httpd]
mod_esi:deliver/2
made to accept binary data.
+ Bernard Duggan
Own Id: OTP-9123
--
cgit v1.2.3
From bf6a8c53023a284b9f2de8d13538db1ab3ff8dee Mon Sep 17 00:00:00 2001
From: Micael Karlberg
Date: Fri, 11 Mar 2011 12:27:47 +0100
Subject: [httpd] Prevent XSS in error pages. Prevent user controlled input
from being interpreted as HTML in error pages by encoding the reserved HTML
characters.
---
lib/inets/src/inets_app/inets.appup.src | 1 +
lib/inets/test/httpd_basic_SUITE.erl | 55 +++++++++++++++++++++++++--------
2 files changed, 43 insertions(+), 13 deletions(-)
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index 7e3785e240..b89ce0fbb2 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -46,6 +46,7 @@
{load_module, http_util, soft_purge, soft_purge, []},
{load_module, httpd_util, soft_purge, soft_purge, [http_util]}
]
+ },
{"5.5.1",
[
{load_module, http_chunk, soft_purge, soft_purge, []}
diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl
index 1cb07c2f5b..ced0d3d6d0 100644
--- a/lib/inets/test/httpd_basic_SUITE.erl
+++ b/lib/inets/test/httpd_basic_SUITE.erl
@@ -29,7 +29,11 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [uri_too_long_414, header_too_long_413, escaped_url_in_error_body].
+ [
+ uri_too_long_414,
+ header_too_long_413,
+ escaped_url_in_error_body
+ ].
groups() ->
[].
@@ -40,6 +44,7 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+
%%--------------------------------------------------------------------
%% Function: init_per_suite(Config) -> Config
%% Config - [tuple()]
@@ -50,6 +55,8 @@ end_per_group(_GroupName, Config) ->
%% variable, but should NOT alter/remove any existing entries.
%%--------------------------------------------------------------------
init_per_suite(Config) ->
+ tsp("init_per_suite -> entry with"
+ "~n Config: ~p", [Config]),
ok = inets:start(),
PrivDir = ?config(priv_dir, Config),
HttpdConf = [{port, 0}, {ipfamily, inet},
@@ -64,6 +71,8 @@ init_per_suite(Config) ->
%% Description: Cleanup after the whole suite
%%--------------------------------------------------------------------
end_per_suite(_Config) ->
+ tsp("end_per_suite -> entry with"
+ "~n Config: ~p", [_Config]),
inets:stop(),
ok.
@@ -79,9 +88,12 @@ end_per_suite(_Config) ->
%% Note: This function is free to add any key/value pairs to the Config
%% variable, but should NOT alter/remove any existing entries.
%%--------------------------------------------------------------------
-init_per_testcase(_Case, Config) ->
+init_per_testcase(Case, Config) ->
+ tsp("init_per_testcase(~w) -> entry with"
+ "~n Config: ~p", [Case, Config]),
Config.
+
%%--------------------------------------------------------------------
%% Function: end_per_testcase(Case, Config) -> _
%% Case - atom()
@@ -90,9 +102,12 @@ init_per_testcase(_Case, Config) ->
%% A list of key/value pairs, holding the test case configuration.
%% Description: Cleanup after each test case
%%--------------------------------------------------------------------
-end_per_testcase(_, Config) ->
+end_per_testcase(Case, Config) ->
+ tsp("end_per_testcase(~w) -> entry with"
+ "~n Config: ~p", [Case, Config]),
Config.
+
%%-------------------------------------------------------------------------
%% Test cases starts here.
%%-------------------------------------------------------------------------
@@ -142,23 +157,30 @@ escaped_url_in_error_body(doc) ->
escaped_url_in_error_body(suite) ->
[];
escaped_url_in_error_body(Config) when is_list(Config) ->
- HttpdConf = ?config(httpd_conf, Config),
+ tsp("escaped_url_in_error_body -> entry with"
+ "~n Config: ~p", [Config]),
+ HttpdConf = ?config(httpd_conf, Config),
{ok, Pid} = inets:start(httpd, [{port, 0} | HttpdConf]),
Info = httpd:info(Pid),
Port = proplists:get_value(port, Info),
- Address = proplists:get_value(bind_address, Info),
- Path = "/this_is_bold",
+ _Address = proplists:get_value(bind_address, Info),
+ Path = "/this_is_bold",
URL = ?URL_START ++ integer_to_list(Port) ++ Path,
EscapedPath = http_uri:encode(Path),
- {ok, {404, Body}} = httpc:request(get, {URL, []},
- [{url_encode, true}, {version, "HTTP/1.0"}],
- [{full_result, false}]),
- EscapedPath = find_URL_path(string:tokens(Body, " ")),
{ok, {404, Body1}} = httpc:request(get, {URL, []},
- [{version, "HTTP/1.0"}], [{full_result, false}]),
+ [{url_encode, true},
+ {version, "HTTP/1.0"}],
+ [{full_result, false}]),
+ EscapedPath = find_URL_path(string:tokens(Body1, " ")),
+ {ok, {404, Body2}} = httpc:request(get, {URL, []},
+ [{url_encode, false},
+ {version, "HTTP/1.0"}],
+ [{full_result, false}]),
HTMLEncodedPath = http_util:html_encode(Path),
- HTMLEncodedPath = find_URL_path(string:tokens(Body1, " ")),
- inets:stop(httpd, Pid).
+ HTMLEncodedPath = find_URL_path(string:tokens(Body2, " ")),
+ inets:stop(httpd, Pid),
+ tsp("escaped_url_in_error_body -> done"),
+ ok.
find_URL_path([]) ->
"";
@@ -166,3 +188,10 @@ find_URL_path(["URL", URL | _]) ->
URL;
find_URL_path([_ | Rest]) ->
find_URL_path(Rest).
+
+
+tsp(F) ->
+ tsp(F, []).
+tsp(F, A) ->
+ test_server:format("~p ~p:" ++ F ++ "~n", [self(), ?MODULE | A]).
+
--
cgit v1.2.3
From 61c6577254568abd92c2d8d00c948cf230e602ca Mon Sep 17 00:00:00 2001
From: Micael Karlberg
Date: Mon, 14 Mar 2011 12:17:12 +0100
Subject: Used the wrong security property names in documentation.
---
lib/inets/doc/src/httpd.xml | 12 +++++------
lib/inets/doc/src/mod_security.xml | 4 ++--
lib/inets/doc/src/notes.xml | 37 +++++++++++++++++++++++++++++++++
lib/inets/src/inets_app/inets.appup.src | 14 ++++++++++---
lib/inets/vsn.mk | 2 +-
5 files changed, 57 insertions(+), 12 deletions(-)
diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml
index 62f4e18f82..91a55f6920 100644
--- a/lib/inets/doc/src/httpd.xml
+++ b/lib/inets/doc/src/httpd.xml
@@ -4,7 +4,7 @@
@@ -162,7 +176,8 @@
are URL-encoded. Added support in http-client to use
URL-encoding. Also added the missing include directory
for the inets application.
- Own Id: OTP-8940 Aux Id: seq11735
+ Own Id: OTP-8940
+ Aux Id: seq11735
--
cgit v1.2.3
From d0f399b4b08b5cd9fb54bec5d71c82b560199c86 Mon Sep 17 00:00:00 2001
From: Micael Karlberg
Date: Tue, 12 Apr 2011 18:06:45 +0200
Subject: Proper release notes.
---
lib/inets/src/inets_app/inets.appup.src | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index df18ffa9e8..c14f8d51f6 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -22,12 +22,14 @@
[
{load_module, ftp, soft_purge, soft_purge, []},
{load_module, http_util, soft_purge, soft_purge, []},
+ {load_module, http_transport, soft_purge, soft_purge, []},
{load_module, httpd_util, soft_purge, soft_purge, [http_util]},
{load_module, httpd_file, soft_purge, soft_purge, []},
{load_module, httpd_log, soft_purge, soft_purge, []},
{load_module, mod_esi, soft_purge, soft_purge, []},
{load_module, httpc, soft_purge, soft_purge, [httpc_handler]},
{load_module, httpc_request, soft_purge, soft_purge, []},
+ {update, httpd_sup, soft, soft_purge, soft_purge, [http_transport]},
{update, httpd_request_handler, soft, soft_purge, soft_purge, []},
{update, httpc_handler, soft, soft_purge, soft_purge, [httpc_request]}
]
@@ -37,12 +39,14 @@
{load_module, ftp, soft_purge, soft_purge, []},
{load_module, http_chunk, soft_purge, soft_purge, []},
{load_module, http_util, soft_purge, soft_purge, []},
+ {load_module, http_transport, soft_purge, soft_purge, []},
{load_module, httpd_util, soft_purge, soft_purge, [http_util]},
{load_module, httpd_file, soft_purge, soft_purge, []},
{load_module, httpd_log, soft_purge, soft_purge, []},
{load_module, mod_esi, soft_purge, soft_purge, []},
{load_module, httpc, soft_purge, soft_purge, [httpc_handler]},
{load_module, httpc_request, soft_purge, soft_purge, []},
+ {update, httpd_sup, soft, soft_purge, soft_purge, [http_transport]},
{update, httpd_request_handler, soft, soft_purge, soft_purge, []},
{update, httpc_handler, soft, soft_purge, soft_purge,
[httpc_request, http_chunk]}
@@ -64,12 +68,14 @@
[
{load_module, ftp, soft_purge, soft_purge, []},
{load_module, http_util, soft_purge, soft_purge, []},
+ {load_module, http_transport, soft_purge, soft_purge, []},
{load_module, httpd_util, soft_purge, soft_purge, [http_util]},
{load_module, httpd_file, soft_purge, soft_purge, []},
{load_module, httpd_log, soft_purge, soft_purge, []},
{load_module, mod_esi, soft_purge, soft_purge, []},
{load_module, httpc, soft_purge, soft_purge, [httpc_handler]},
{load_module, httpc_request, soft_purge, soft_purge, []},
+ {update, httpd_sup, soft, soft_purge, soft_purge, [http_transport]},
{update, httpd_request_handler, soft, soft_purge, soft_purge, []},
{update, httpc_handler, soft, soft_purge, soft_purge, [httpc_request]}
]
@@ -79,12 +85,14 @@
{load_module, ftp, soft_purge, soft_purge, []},
{load_module, http_chunk, soft_purge, soft_purge, []},
{load_module, http_util, soft_purge, soft_purge, []},
+ {load_module, http_transport, soft_purge, soft_purge, []},
{load_module, httpd_util, soft_purge, soft_purge, [http_util]},
{load_module, httpd_file, soft_purge, soft_purge, []},
{load_module, httpd_log, soft_purge, soft_purge, []},
{load_module, mod_esi, soft_purge, soft_purge, []},
{load_module, httpc, soft_purge, soft_purge, [httpc_handler]},
{load_module, httpc_request, soft_purge, soft_purge, []},
+ {update, httpd_sup, soft, soft_purge, soft_purge, [http_transport]},
{update, httpd_request_handler, soft, soft_purge, soft_purge, []},
{update, httpc_handler, soft, soft_purge, soft_purge,
[httpc_request, http_chunk]}
--
cgit v1.2.3
From 5488c7843c8930d14d1d0d2ec0aa23d0d491afbc Mon Sep 17 00:00:00 2001
From: Micael Karlberg
Date: Tue, 19 Apr 2011 13:37:06 +0200
Subject: Default ssl kind changed to essl (from ossl).
---
lib/inets/doc/src/httpc.xml | 21 ++++++---------------
lib/inets/doc/src/httpd.xml | 2 +-
lib/inets/doc/src/notes.xml | 13 +++++++++++++
lib/inets/src/http_lib/http_internal.hrl | 6 +++---
4 files changed, 23 insertions(+), 19 deletions(-)
diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml
index 532f5eefde..f6b6827e93 100644
--- a/lib/inets/doc/src/httpc.xml
+++ b/lib/inets/doc/src/httpc.xml
@@ -105,17 +105,8 @@ filename() = string()
SSL DATA TYPES
- Some type definitions relevant when using https,
- for details ssl(3):
-
+ See ssl(3) for information
+ about ssl options (ssloptions()).
@@ -175,9 +166,9 @@ ssl_options() = {verify, code()} |
http_options() = [http_option()]
http_option() = {timeout, timeout()} |
{connect_timeout, timeout()} |
- {ssl, ssl_options()} |
- {ossl, ssl_options()} |
- {essl, ssl_options()} |
+ {ssl, ssloptions()} |
+ {ossl, ssloptions()} |
+ {essl, ssloptions()} |
{autoredirect, boolean()} |
{proxy_auth, {userstring(), passwordstring()}} |
{version, http_version()} |
@@ -236,7 +227,7 @@ ssl_options() = {verify, code()} |
-
This is the default ssl config option, currently defaults to
- ossl, see below.
+ essl, see below.
Defaults to [].
diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml
index ac49a37296..edacb73b65 100644
--- a/lib/inets/doc/src/httpd.xml
+++ b/lib/inets/doc/src/httpd.xml
@@ -154,7 +154,7 @@
ossl specifically uses the OpenSSL based (old) SSL.
essl specifically uses the Erlang based (new) SSL.
When using ssl it currently defaults to
- ossl.
+ essl.
Defaults to ip_comm.
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index df3bf19066..b885bcbcdb 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -91,6 +91,19 @@
Aux Id: seq11819
+ -
+
The default ssl kind has now been changed to essl.
+ ossl will work for as long as the ssl application
+ supports it.
+ See the httpd
+ socket_type
+ communication property or the httpc
+ request/4,5 function
+ for more info.
+ Own Id: OTP-9230
+ *** POTENTIAL INCOMPATIBILITY ***
+
+
diff --git a/lib/inets/src/http_lib/http_internal.hrl b/lib/inets/src/http_lib/http_internal.hrl
index 5440f214b5..2e924667c6 100644
--- a/lib/inets/src/http_lib/http_internal.hrl
+++ b/lib/inets/src/http_lib/http_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,8 +28,8 @@
-define(HTTP_MAX_URI_SIZE, nolimit).
-ifndef(HTTP_DEFAULT_SSL_KIND).
--define(HTTP_DEFAULT_SSL_KIND, ossl).
-%% -define(HTTP_DEFAULT_SSL_KIND, essl).
+%% -define(HTTP_DEFAULT_SSL_KIND, ossl).
+-define(HTTP_DEFAULT_SSL_KIND, essl).
-endif. % -ifdef(HTTP_DEFAULT_SSL_KIND).
--
cgit v1.2.3
From 29d4a0f745b69f7d2a75664b857b6ad65fca920d Mon Sep 17 00:00:00 2001
From: Micael Karlberg
Date: Tue, 19 Apr 2011 13:43:27 +0200
Subject: Updated appup file.
---
lib/inets/src/inets_app/inets.appup.src | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index c14f8d51f6..0a590c9c36 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -24,6 +24,7 @@
{load_module, http_util, soft_purge, soft_purge, []},
{load_module, http_transport, soft_purge, soft_purge, []},
{load_module, httpd_util, soft_purge, soft_purge, [http_util]},
+ {load_module, httpd_conf, soft_purge, soft_purge, []},
{load_module, httpd_file, soft_purge, soft_purge, []},
{load_module, httpd_log, soft_purge, soft_purge, []},
{load_module, mod_esi, soft_purge, soft_purge, []},
@@ -41,6 +42,7 @@
{load_module, http_util, soft_purge, soft_purge, []},
{load_module, http_transport, soft_purge, soft_purge, []},
{load_module, httpd_util, soft_purge, soft_purge, [http_util]},
+ {load_module, httpd_conf, soft_purge, soft_purge, []},
{load_module, httpd_file, soft_purge, soft_purge, []},
{load_module, httpd_log, soft_purge, soft_purge, []},
{load_module, mod_esi, soft_purge, soft_purge, []},
@@ -70,6 +72,7 @@
{load_module, http_util, soft_purge, soft_purge, []},
{load_module, http_transport, soft_purge, soft_purge, []},
{load_module, httpd_util, soft_purge, soft_purge, [http_util]},
+ {load_module, httpd_conf, soft_purge, soft_purge, []},
{load_module, httpd_file, soft_purge, soft_purge, []},
{load_module, httpd_log, soft_purge, soft_purge, []},
{load_module, mod_esi, soft_purge, soft_purge, []},
@@ -87,6 +90,7 @@
{load_module, http_util, soft_purge, soft_purge, []},
{load_module, http_transport, soft_purge, soft_purge, []},
{load_module, httpd_util, soft_purge, soft_purge, [http_util]},
+ {load_module, httpd_conf, soft_purge, soft_purge, []},
{load_module, httpd_file, soft_purge, soft_purge, []},
{load_module, httpd_log, soft_purge, soft_purge, []},
{load_module, mod_esi, soft_purge, soft_purge, []},
--
cgit v1.2.3
From 5d32eaf750cff98d242c8048eeb6b49c94fb6ee6 Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin
Date: Wed, 11 May 2011 12:05:11 +0200
Subject: Fixed httpc manager crash
httpc manager crashes.When a request results in a retry, the request
id will be "reused" in the previous implementation a race condition
could occur causing the manager to crash. This is now avoided by using
proc_lib:init_ack and gen_server:enter_loop to allow more advanced
initialization of httpc_handlers without blocking the httpc_manger
and eliminating extra processes that can cause race conditions.
---
lib/inets/src/http_client/httpc_handler.erl | 256 ++++--------
lib/inets/src/http_client/httpc_handler_sup.erl | 8 +-
lib/inets/src/http_client/httpc_manager.erl | 509 +++++-------------------
lib/inets/src/http_client/httpc_request.erl | 8 +-
lib/inets/src/inets_app/inets.appup.src | 60 +--
lib/inets/test/httpc_SUITE.erl | 211 ++++++----
6 files changed, 324 insertions(+), 728 deletions(-)
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index 5e22400fe0..1f0e012e7e 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -29,10 +29,10 @@
%%--------------------------------------------------------------------
%% Internal Application API
-export([
- start_link/2,
- connect_and_send/2,
+ start_link/4,
+ %% connect_and_send/2,
send/2,
- cancel/2,
+ cancel/3,
stream/3,
stream_next/1,
info/1
@@ -51,7 +51,7 @@
-record(state,
{
request, % #request{}
- session, % #tcp_session{}
+ session, % #session{}
status_line, % {Version, StatusCode, ReasonPharse}
headers, % #http_response_h{}
body, % binary()
@@ -94,13 +94,9 @@
%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
-start_link(Options, ProfileName) ->
- Args = [Options, ProfileName],
- gen_server:start_link(?MODULE, Args, []).
-
-connect_and_send(Request, HandlerPid) ->
- call({connect_and_send, Request}, HandlerPid).
-
+start_link(Parent, Request, Options, ProfileName) ->
+ {ok, proc_lib:start_link(?MODULE, init, [[Parent, Request, Options,
+ ProfileName]])}.
%%--------------------------------------------------------------------
%% Function: send(Request, Pid) -> ok
@@ -122,8 +118,8 @@ send(Request, Pid) ->
%% Description: Cancels a request. Intended to be called by the httpc
%% manager process.
%%--------------------------------------------------------------------
-cancel(RequestId, Pid) ->
- cast({cancel, RequestId}, Pid).
+cancel(RequestId, Pid, From) ->
+ cast({cancel, RequestId, From}, Pid).
%%--------------------------------------------------------------------
@@ -229,16 +225,27 @@ stream(BodyPart, Request,_) -> % only 200 and 206 responses can be streamed
%% but we do not want that so errors will be handled by the process
%% sending an init_error message to itself.
%%--------------------------------------------------------------------
-init([Options, ProfileName]) ->
- ?hcrv("init - starting", [{options, Options}, {profile, ProfileName}]),
+init([Parent, Request, Options, ProfileName]) ->
process_flag(trap_exit, true),
- handle_verbose(Options#options.verbose),
- State = #state{status = undefined,
- options = Options,
- profile_name = ProfileName},
- ?hcrd("init - started", []),
- {ok, State}.
+ %% Do not let initial tcp-connection block the manager-process
+ proc_lib:init_ack(Parent, self()),
+ handle_verbose(Options#options.verbose),
+ Address = handle_proxy(Request#request.address, Options#options.proxy),
+ {ok, State} =
+ case {Address /= Request#request.address, Request#request.scheme} of
+ {true, https} ->
+ Error = https_through_proxy_is_not_currently_supported,
+ self() ! {init_error,
+ Error, httpc_response:error(Request, Error)},
+ {ok, #state{request = Request, options = Options,
+ status = ssl_tunnel}};
+ {_, _} ->
+ connect_and_send_first_request(Address, Request,
+ #state{options = Options,
+ profile_name = ProfileName})
+ end,
+ gen_server:enter_loop(?MODULE, [], State).
%%--------------------------------------------------------------------
%% Function: handle_call(Request, From, State) -> {reply, Reply, State} |
@@ -249,41 +256,6 @@ init([Options, ProfileName]) ->
%% {stop, Reason, State} (terminate/2 is called)
%% Description: Handling call messages
%%--------------------------------------------------------------------
-
-
-%% This is the first request, the reason the proc was started
-handle_call({connect_and_send, #request{address = Address0,
- scheme = Scheme} = Request},
- _From,
- #state{options = #options{proxy = Proxy},
- status = undefined,
- session = undefined} = State) ->
- ?hcrv("connect and send", [{address0, Address0}, {proxy, Proxy}]),
- Address = handle_proxy(Address0, Proxy),
- if
- ((Address =/= Address0) andalso (Scheme =:= https)) ->
- %% This is what we should do if and when ssl supports
- %% "socket upgrading"
- %%send_ssl_tunnel_request(Address, Request,
- %% #state{options = Options,
- %% status = ssl_tunnel});
- Reason = {failed_connecting,
- https_through_proxy_is_not_currently_supported},
- %% Send a reply to the original caller
- ErrorResponse = httpc_response:error(Request, Reason),
- httpc_response:send(Request#request.from, ErrorResponse),
- %% Reply to the manager
- ErrorReply = {error, Reason},
- {stop, normal, ErrorReply, State};
- true ->
- case connect_and_send_first_request(Address, Request, State) of
- {ok, NewState} ->
- {reply, ok, NewState};
- {stop, Error, NewState} ->
- {stop, normal, Error, NewState}
- end
- end;
-
handle_call(#request{address = Addr} = Request, _,
#state{status = Status,
session = #session{type = pipeline} = Session,
@@ -445,25 +417,27 @@ handle_call(info, _, State) ->
%% handle_keep_alive_queue/2 on the other hand will just skip the
%% request as if it was never issued as in this case the request will
%% not have been sent.
-handle_cast({cancel, RequestId},
+handle_cast({cancel, RequestId, From},
#state{request = #request{id = RequestId} = Request,
profile_name = ProfileName,
canceled = Canceled} = State) ->
?hcrv("cancel current request", [{request_id, RequestId},
{profile, ProfileName},
{canceled, Canceled}]),
- httpc_manager:request_canceled(RequestId, ProfileName),
+ httpc_manager:request_canceled(RequestId, ProfileName, From),
?hcrv("canceled", []),
{stop, normal,
State#state{canceled = [RequestId | Canceled],
request = Request#request{from = answer_sent}}};
-handle_cast({cancel, RequestId},
+handle_cast({cancel, RequestId, From},
#state{profile_name = ProfileName,
+ request = #request{id = CurrId},
canceled = Canceled} = State) ->
- ?hcrv("cancel", [{request_id, RequestId},
+ ?hcrv("cancel", [{request_id, RequestId},
+ {curr_req_id, CurrId},
{profile, ProfileName},
{canceled, Canceled}]),
- httpc_manager:request_canceled(RequestId, ProfileName),
+ httpc_manager:request_canceled(RequestId, ProfileName, From),
?hcrv("canceled", []),
{noreply, State#state{canceled = [RequestId | Canceled]}};
@@ -872,62 +846,55 @@ connect(SocketType, ToAddress,
Opts3 = [IpFamily | Opts2],
http_transport:connect(SocketType, ToAddress, Opts3, Timeout)
end.
-
-connect_and_send_first_request(Address,
- #request{settings = Settings,
- headers = Headers,
- address = OrigAddress,
- scheme = Scheme} = Request,
- #state{options = Options} = State) ->
-
- ?hcrd("connect",
- [{address, Address}, {request, Request}, {options, Options}]),
+connect_and_send_first_request(Address, Request, #state{options = Options} = State) ->
SocketType = socket_type(Request),
- ConnTimeout = Settings#http_options.connect_timeout,
+ ConnTimeout = (Request#request.settings)#http_options.connect_timeout,
+ ?hcri("connect",
+ [{address, Address}, {request, Request}, {options, Options}]),
case connect(SocketType, Address, Options, ConnTimeout) of
{ok, Socket} ->
- Session = #session{id = {OrigAddress, self()},
- scheme = Scheme,
- socket = Socket,
- socket_type = SocketType},
- ?hcrd("connected - now send first request", [{socket, Socket}]),
+ ClientClose =
+ httpc_request:is_client_closing(
+ Request#request.headers),
+ SessionType = httpc_manager:session_type(Options),
+ SocketType = socket_type(Request),
+ Session = #session{id = {Request#request.address, self()},
+ scheme = Request#request.scheme,
+ socket = Socket,
+ socket_type = SocketType,
+ client_close = ClientClose,
+ type = SessionType},
+ ?hcri("connected - now send first request", [{socket, Socket}]),
+
case httpc_request:send(Address, Session, Request) of
ok ->
- ?hcrd("first request sent", []),
- ClientClose =
- httpc_request:is_client_closing(Headers),
- SessionType = httpc_manager:session_type(Options),
- Session2 =
- Session#session{client_close = ClientClose,
- type = SessionType},
- TmpState =
- State#state{request = Request,
- session = Session2,
- mfa = init_mfa(Request, State),
- status_line = init_status_line(Request),
- headers = undefined,
- body = undefined,
- status = new},
- ?hcrt("activate socket", []),
- activate_once(Session),
+ ?hcri("first request sent", []),
+ TmpState = State#state{request = Request,
+ session = Session,
+ mfa = init_mfa(Request, State),
+ status_line =
+ init_status_line(Request),
+ headers = undefined,
+ body = undefined,
+ status = new},
+ http_transport:setopts(SocketType,
+ Socket, [{active, once}]),
NewState = activate_request_timeout(TmpState),
{ok, NewState};
-
- {error, Reason} = Error ->
- ?hcrv("failed sending request", [{reason, Reason}]),
- {stop, Error,
- State#state{session = {send_failed, Reason},
- request = Request}}
+ {error, Reason} ->
+ self() ! {init_error, error_sending,
+ httpc_response:error(Request, Reason)},
+ {ok, State#state{request = Request,
+ session =
+ #session{socket = Socket}}}
end;
-
- {error, Reason} = Error ->
- ?hcri("connect failed", [{reason, Reason}]),
- {stop, Error, State#state{session = {connect_failed, Reason},
- request = Request}}
+ {error, Reason} ->
+ self() ! {init_error, error_connecting,
+ httpc_response:error(Request, Reason)},
+ {ok, State#state{request = Request}}
end.
-
handler_info(#state{request = Request,
session = Session,
status_line = _StatusLine,
@@ -1167,12 +1134,12 @@ handle_response(#state{request = Request,
{ok, Msg, Data} ->
?hcrd("handle response - ok", []),
end_stream(StatusLine, Request),
- NewState = answer_request(Request, Msg, State),
+ NewState = maybe_send_answer(Request, Msg, State),
handle_queue(NewState, Data);
{stop, Msg} ->
?hcrd("handle response - stop", [{msg, Msg}]),
end_stream(StatusLine, Request),
- NewState = answer_request(Request, Msg, State),
+ NewState = maybe_send_answer(Request, Msg, State),
{stop, normal, NewState}
end.
@@ -1242,7 +1209,8 @@ handle_pipeline(#state{status = pipeline,
%% See comment for handle_cast({cancel, RequestId})
{stop, normal,
State#state{request =
- NextRequest#request{from = answer_sent}}};
+ NextRequest#request{from = answer_sent},
+ pipeline = Pipeline}};
false ->
?hcrv("next request", [{request, NextRequest}]),
NewSession =
@@ -1443,6 +1411,7 @@ answer_request(#request{id = RequestId, from = From} = Request, Msg,
Timer = {RequestId, TimerRef},
cancel_timer(TimerRef, {timeout, Request#request.id}),
httpc_manager:request_done(RequestId, ProfileName),
+
State#state{request = Request#request{from = answer_sent},
timers =
Timers#timers{request_timers =
@@ -1662,67 +1631,6 @@ 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}},
-%% State) ->
-%% %% A ssl tunnel request is a special http request that looks like
-%% %% CONNECT host:port HTTP/1.1
-%% SslTunnelRequest = #request{method = connect, scheme = http,
-%% headers =
-%% #http_request_h{
-%% host = Host,
-%% address = Address,
-%% path = Host ++ ":",
-%% pquery = integer_to_list(Port),
-%% other = [{ "Proxy-Connection", "keep-alive"}]},
-%% Ipv6 = (State#state.options)#options.ipv6,
-%% SocketType = socket_type(SslTunnelRequest),
-%% case http_transport:connect(SocketType,
-%% SslTunnelRequest#request.address, Ipv6) of
-%% {ok, Socket} ->
-%% case httpc_request:send(Address, SslTunnelRequest, Socket) of
-%% ok ->
-%% Session = #tcp_session{id =
-%% {SslTunnelRequest#request.address,
-%% self()},
-%% scheme =
-%% SslTunnelRequest#request.scheme,
-%% socket = Socket},
-%% NewState = State#state{mfa =
-%% {httpc_response, parse,
-%% [State#state.max_header_size]},
-%% request = Request,
-%% session = Session},
-%% http_transport:setopts(socket_type(
-%% SslTunnelRequest#request.scheme),
-%% Socket,
-%% [{active, once}]),
-%% {ok, NewState};
-%% {error, Reason} ->
-%% self() ! {init_error, error_sending,
-%% httpc_response:error(Request, Reason)},
-%% {ok, State#state{request = Request,
-%% session = #tcp_session{socket =
-%% Socket}}}
-%% end;
-%% {error, Reason} ->
-%% self() ! {init_error, error_connecting,
-%% httpc_response:error(Request, Reason)},
-%% {ok, State#state{request = Request}}
-%% end.
-
-%% d(F) ->
-%% d(F, []).
-
-%% d(F, A) ->
-%% d(get(dbg), F, A).
-
-%% d(true, F, A) ->
-%% io:format(user, "~w:~w:" ++ F ++ "~n", [self(), ?MODULE | A]);
-%% d(_, _, _) ->
-%% ok.
-
send_raw(#session{socket = Socket, socket_type = SocketType},
{ProcessBody, Acc}) when is_function(ProcessBody, 1) ->
@@ -1756,11 +1664,5 @@ call(Msg, Pid, Timeout) ->
cast(Msg, Pid) ->
gen_server:cast(Pid, Msg).
-
-%% to(To, Start) when is_integer(Start) andalso (Start >= 0) ->
-%% http_util:timeout(To, Start);
-%% to(To, _Start) ->
-%% http_util:timeout(To, t()).
-
t() ->
http_util:timestamp().
diff --git a/lib/inets/src/http_client/httpc_handler_sup.erl b/lib/inets/src/http_client/httpc_handler_sup.erl
index 2a69fd15d0..f7a0b014b3 100644
--- a/lib/inets/src/http_client/httpc_handler_sup.erl
+++ b/lib/inets/src/http_client/httpc_handler_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -23,7 +23,7 @@
%% API
-export([start_link/0]).
--export([start_child/2]).
+-export([start_child/1]).
%% Supervisor callback
-export([init/1]).
@@ -34,11 +34,9 @@
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
-start_child(Options, Profile) ->
- Args = [Options, Profile],
+start_child(Args) ->
supervisor:start_child(?MODULE, Args).
-
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index 591cb78c29..7f66b477eb 100644
--- a/lib/inets/src/http_client/httpc_manager.erl
+++ b/lib/inets/src/http_client/httpc_manager.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -29,7 +29,7 @@
start_link/3,
request/2,
cancel_request/2,
- request_canceled/2,
+ request_canceled/3,
request_done/2,
retry_request/2,
redirect_request/2,
@@ -66,6 +66,7 @@
state % State of the handler: initiating | started | operational | canceled
}).
+-define(DELAY, 500).
%%====================================================================
%% Internal Application API
@@ -158,7 +159,8 @@ cancel_request(RequestId, ProfileName) ->
%% be called by the httpc handler process.
%%--------------------------------------------------------------------
-request_canceled(RequestId, ProfileName) ->
+request_canceled(RequestId, ProfileName, From) ->
+ gen_server:reply(From, ok),
cast(ProfileName, {request_canceled, RequestId}).
@@ -355,44 +357,32 @@ do_init(ProfileName, CookiesDir) ->
%% {stop, Reason, State} (terminate/2 is called)
%% Description: Handling call messages
%%--------------------------------------------------------------------
-handle_call({request, Request}, _From, State) ->
- ?hcrv("request", [{request, Request}]),
+handle_call({request, Request}, _, State) ->
+ ?hcri("request", [{request, Request}]),
case (catch handle_request(Request, State)) of
- {ok, ReqId, NewState} ->
- {reply, {ok, ReqId}, NewState};
-
+ {reply, Msg, NewState} ->
+ {reply, Msg, NewState};
Error ->
- NewError = {error, {failed_process_request, Error}},
- {reply, NewError, State}
+ {stop, Error, httpc_response:error(Request, Error), State}
end;
-
-handle_call({cancel_request, RequestId}, From,
- #state{handler_db = HandlerDb} = State) ->
- ?hcrv("cancel_request", [{request_id, RequestId}]),
+
+handle_call({cancel_request, RequestId}, From, State) ->
+ ?hcri("cancel_request", [{request_id, RequestId}]),
case ets:lookup(State#state.handler_db, RequestId) of
[] ->
- ?hcrd("nothing to cancel", []),
- Reply = ok, %% Nothing to cancel
- {reply, Reply, State};
-
- [#handler_info{handler = Pid}] when is_pid(Pid) ->
- ?hcrd("found operational handler for this request",
- [{handler, Pid}]),
- httpc_handler:cancel(RequestId, Pid),
- {noreply, State#state{cancel =
- [{RequestId, Pid, From} |
- State#state.cancel]}};
-
- [#handler_info{starter = Pid, state = HandlerState}]
- when is_pid(Pid) ->
- ?hcri("found *initiating* handler for this request",
- [{starter, Pid}, {state, HandlerState}]),
- ets:update_element(HandlerDb, RequestId,
- {#handler_info.state, canceled}),
+ %% The request has allready compleated make sure
+ %% it is deliverd to the client process queue so
+ %% it can be thrown away by httpc:cancel_request
+ %% This delay is hopfully a temporary workaround.
+ %% Note that it will not not delay the manager,
+ %% only the client that called httpc:cancel_request
+ timer:apply_after(?DELAY, gen_server, reply, [From, ok]),
+ {noreply, State};
+ [{_, Pid, _}] ->
+ httpc_handler:cancel(RequestId, Pid, From),
{noreply, State#state{cancel =
- [{RequestId, Pid, From} |
+ [{RequestId, Pid, From} |
State#state.cancel]}}
-
end;
handle_call(reset_cookies, _, #state{cookie_db = CookieDb} = State) ->
@@ -437,43 +427,16 @@ handle_call(Req, From, #state{profile_name = ProfileName} = State) ->
%%--------------------------------------------------------------------
handle_cast({retry_or_redirect_request, {Time, Request}},
#state{profile_name = ProfileName} = State) ->
- ?hcrv("retry or redirect request", [{time, Time}, {request, Request}]),
- case timer:apply_after(Time, ?MODULE, retry_request,
- [Request, ProfileName]) of
- {ok, _} ->
- {noreply, State};
- {error, Reason} ->
- error_report(ProfileName,
- "failed scheduling retry/redirect request"
- "~n Time: ~p"
- "~n Request: ~p"
- "~n Reason: ~p", [Time, Request, Reason]),
- {noreply, State}
- end;
+ {ok, _} = timer:apply_after(Time, ?MODULE, retry_request, [Request, ProfileName]),
+ {noreply, State};
-handle_cast({retry_or_redirect_request, Request},
- #state{profile_name = Profile,
- handler_db = HandlerDb} = State) ->
- ?hcrv("retry or redirect request", [{request, Request}]),
+handle_cast({retry_or_redirect_request, Request}, State) ->
case (catch handle_request(Request, State)) of
- {ok, _, NewState} ->
+ {reply, {ok, _}, NewState} ->
{noreply, NewState};
-
Error ->
- 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}
+ httpc_response:error(Request, Error),
+ {stop, Error, State}
end;
handle_cast({request_canceled, RequestId}, State) ->
@@ -482,7 +445,6 @@ handle_cast({request_canceled, RequestId}, State) ->
case lists:keysearch(RequestId, 1, State#state.cancel) of
{value, Entry = {RequestId, _, From}} ->
?hcrt("found in cancel", [{from, From}]),
- gen_server:reply(From, ok),
{noreply,
State#state{cancel = lists:delete(Entry, State#state.cancel)}};
Else ->
@@ -539,8 +501,6 @@ handle_cast(Msg, #state{profile_name = ProfileName} = State) ->
"recived unknown message"
"~n Msg: ~p", [Msg]),
{noreply, State}.
-
-
%%--------------------------------------------------------------------
%% Function: handle_info(Info, State) -> {noreply, State} |
@@ -548,39 +508,17 @@ handle_cast(Msg, #state{profile_name = ProfileName} = State) ->
%% {stop, Reason, State} (terminate/2 is called)
%% Description: Handling all non call/cast messages
%%---------------------------------------------------------
-
-handle_info({started, StarterPid, ReqId, HandlerPid}, State) ->
- handle_started(StarterPid, ReqId, HandlerPid, State),
- {noreply, State};
-
-handle_info({connect_and_send, StarterPid, ReqId, HandlerPid, Res}, State) ->
- handle_connect_and_send(StarterPid, ReqId, HandlerPid, Res, State),
- {noreply, State};
-
-handle_info({failed_starting_handler, StarterPid, ReqId, Res}, State) ->
- handle_failed_starting_handler(StarterPid, ReqId, Res, State),
- {noreply, State};
-
-handle_info({'EXIT', Pid, Reason}, #state{handler_db = HandlerDb} = State) ->
- maybe_handle_terminating_starter(Pid, Reason, HandlerDb),
+handle_info({'EXIT', _, _}, State) ->
+ %% Handled in DOWN
{noreply, State};
-
handle_info({'DOWN', _, _, Pid, _}, State) ->
-
- %%
- %% Normally this should have been cleaned up already
- %% (when receiving {request_done, PequestId}), but
- %% just in case there is a glitch, cleanup anyway.
- %%
-
- Pattern = #handler_info{handler = Pid, _ = '_'},
- ets:match_delete(State#state.handler_db, Pattern),
+ ets:match_delete(State#state.handler_db, {'_', Pid, '_'}),
%% If there where any canceled request, handled by the
%% the process that now has terminated, the
%% cancelation can be viewed as sucessfull!
- NewCanceledList =
- lists:foldl(fun({_, HandlerPid, From} = Entry, Acc) ->
+ NewCanceldList =
+ lists:foldl(fun(Entry = {_, HandlerPid, From}, Acc) ->
case HandlerPid of
Pid ->
gen_server:reply(From, ok),
@@ -589,15 +527,13 @@ handle_info({'DOWN', _, _, Pid, _}, State) ->
Acc
end
end, State#state.cancel, State#state.cancel),
- {noreply, State#state{cancel = NewCanceledList}};
-
-handle_info(Info, #state{profile_name = ProfileName} = State) ->
- error_report(ProfileName,
- "received unknown info"
- "~n Info: ~p", [Info]),
+ {noreply, State#state{cancel = NewCanceldList}};
+handle_info(Info, State) ->
+ Report = io_lib:format("Unknown message in "
+ "httpc_manager:handle_info ~p~n", [Info]),
+ error_logger:error_report(Report),
{noreply, State}.
-
%%--------------------------------------------------------------------
%% Function: terminate(Reason, State) -> _ (ignored by gen_server)
%% Description: Shutdown the httpc_handler
@@ -655,224 +591,79 @@ get_handler_info(Tab) ->
{Pid, State} <- Handlers2],
Handlers3.
-
-%%
-%% The request handler process is started asynchronously by a
-%% "starter process". When the handler has sucessfully been started,
-%% this message (started) is sent.
-%%
-
-handle_started(StarterPid, ReqId, HandlerPid,
- #state{profile_name = Profile,
- handler_db = HandlerDb}) ->
- case ets:lookup(HandlerDb, ReqId) of
- [#handler_info{state = initiating} = HandlerInfo] ->
- ?hcri("received started ack for initiating handler", []),
- %% As a last resort, make sure we know when it exits,
- %% in case it forgets to notify us.
- %% We dont need to know the ref id?
- erlang:monitor(process, HandlerPid),
- HandlerInfo2 = HandlerInfo#handler_info{handler = HandlerPid,
- state = started},
- ets:insert(HandlerDb, HandlerInfo2),
- ok;
-
- [#handler_info{state = State}] ->
- error_report(Profile,
- "unexpected (started) message for handler (~p) in state "
- "~p regarding request ~p - ignoring", [HandlerPid, State, ReqId]),
- ?hcri("received unexpected started message", [{state, State}]),
- ok;
-
- [] ->
- error_report(Profile,
- "unknown handler ~p (~p) started for request ~w - canceling",
- [HandlerPid, StarterPid, ReqId]),
- httpc_handler:cancel(ReqId, HandlerPid)
- end.
-
-
-%%
-%% The request handler process is started asynchronously by a
-%% "starter process". When that process terminates it sends
-%% one of two messages. These ara handled by the two functions
-%% below.
-%%
-
-handle_connect_and_send(_StarterPid, ReqId, HandlerPid, Result,
- #state{profile_name = Profile,
- handler_db = HandlerDb}) ->
- case ets:lookup(HandlerDb, ReqId) of
- [#handler_info{state = started} = HandlerInfo] when Result =:= ok ->
- ?hcri("received connect-and-send ack for started handler", []),
- HandlerInfo2 = HandlerInfo#handler_info{starter = undefined,
- handler = HandlerPid,
- state = operational},
- ets:insert(HandlerDb, HandlerInfo2),
- ok;
-
- [#handler_info{state = canceled} = HandlerInfo] when Result =:= ok ->
- ?hcri("received connect-and-send ack for canceled handler", []),
- httpc_handler:cancel(ReqId, HandlerPid),
- HandlerInfo2 = HandlerInfo#handler_info{starter = undefined,
- handler = HandlerPid},
- ets:insert(HandlerDb, HandlerInfo2),
- ok;
-
- [#handler_info{state = State}] when Result =/= ok ->
- error_report(Profile,
- "handler (~p, ~w) failed to connect and/or "
- "send request ~p"
- "~n Result: ~p",
- [HandlerPid, State, ReqId, Result]),
- ?hcri("received connect-and-send error",
- [{result, Result}, {state, State}]),
- %% We don't need to send a response to the original caller
- %% because the handler already sent one in its terminate
- %% function.
- ets:delete(HandlerDb, ReqId),
- ok;
-
- [] ->
- ?hcri("handler successfully started "
- "for unknown request => canceling",
- [{profile, Profile},
- {handler, HandlerPid},
- {request, ReqId}]),
- httpc_handler:cancel(ReqId, HandlerPid)
- end.
-
-
-handle_failed_starting_handler(_StarterPid, ReqId, Error,
- #state{profile_name = Profile,
- handler_db = HandlerDb}) ->
- case ets:lookup(HandlerDb, ReqId) of
- [#handler_info{state = canceled}] ->
- error_report(Profile,
- "failed starting handler for request ~p"
- "~n Error: ~p", [ReqId, Error]),
- request_canceled(Profile, ReqId), % Fake signal from handler
- ets:delete(HandlerDb, ReqId),
- ok;
-
- [#handler_info{from = From}] ->
- error_report(Profile,
- "failed starting handler for request ~p"
- "~n Error: ~p", [ReqId, Error]),
- Reason2 =
- case Error of
- {error, Reason} ->
- {failed_connecting, Reason};
- _ ->
- {failed_connecting, Error}
- end,
- DummyReq = #request{id = ReqId},
- httpc_response:send(From, httpc_response:error(DummyReq, Reason2)),
- ets:delete(HandlerDb, ReqId),
- ok;
-
- [] ->
- error_report(Profile,
- "failed starting handler for unknown request ~p"
- "~n Error: ~p", [ReqId, Error]),
- ok
- end.
-
-
-maybe_handle_terminating_starter(MeybeStarterPid, Reason, HandlerDb) ->
- Pattern = #handler_info{starter = MeybeStarterPid, _ = '_'},
- case ets:match_object(HandlerDb, Pattern) of
- [#handler_info{id = ReqId, from = From, state = initiating}] ->
- %% The starter process crashed before it could start the
- %% the handler process, therefor we need to answer the
- %% original caller.
- ?hcri("starter process crashed bfore starting handler",
- [{starter, MeybeStarterPid}, {reason, Reason}]),
- Reason2 =
- case Reason of
- {error, Error} ->
- {failed_connecting, Error};
- _ ->
- {failed_connecting, Reason}
- end,
- DummyReq = #request{id = ReqId},
- httpc_response:send(From, httpc_response:error(DummyReq, Reason2)),
- ets:delete(HandlerDb, ReqId),
- ok;
-
- [#handler_info{state = State} = HandlerInfo] ->
- %% The starter process crashed after the handler was started.
- %% The handler will answer to the original caller.
- ?hcri("starter process crashed after starting handler",
- [{starter, MeybeStarterPid}, {reason, Reason}, {state, State}]),
- HandlerInfo2 = HandlerInfo#handler_info{starter = undefined},
- ets:insert(HandlerDb, HandlerInfo2),
- ok;
-
- _ ->
- ok
- end.
-
-
-%% -----
-%% Act as an HTTP/0.9 client that does not know anything
-%% about persistent connections
handle_request(#request{settings =
- #http_options{version = "HTTP/0.9"}} = Request0,
+ #http_options{version = "HTTP/0.9"}} = Request,
State) ->
- Request1 = handle_cookies(generate_request_id(Request0), State),
- Hdrs0 = Request1#request.headers,
- Hdrs1 = Hdrs0#http_request_h{connection = undefined},
- Request2 = Request1#request{headers = Hdrs1},
- create_handler_starter(Request2, State),
- {ok, Request2#request.id, State};
-
-%% -----
-%% Act as an HTTP/1.0 client that does not
-%% use persistent connections
+ %% Act as an HTTP/0.9 client that does not know anything
+ %% about persistent connections
+
+ NewRequest = handle_cookies(generate_request_id(Request), State),
+ NewHeaders =
+ (NewRequest#request.headers)#http_request_h{connection
+ = undefined},
+ start_handler(NewRequest#request{headers = NewHeaders}, State),
+ {reply, {ok, NewRequest#request.id}, State};
+
handle_request(#request{settings =
- #http_options{version = "HTTP/1.0"}} = Request0,
+ #http_options{version = "HTTP/1.0"}} = Request,
State) ->
- Request1 = handle_cookies(generate_request_id(Request0), State),
- Hdrs0 = Request1#request.headers,
- Hdrs1 = Hdrs0#http_request_h{connection = "close"},
- Request2 = Request1#request{headers = Hdrs1},
- create_handler_starter(Request2, State),
- {ok, Request2#request.id, State};
-
-
-%% -----
-handle_request(#request{method = Method,
- address = Address,
- scheme = Scheme} = Request0,
- #state{options = Opts} = State) ->
- Request1 = handle_cookies(generate_request_id(Request0), State),
- SessionType = session_type(Opts),
- case select_session(Method, Address, Scheme, SessionType, State) of
+ %% Act as an HTTP/1.0 client that does not
+ %% use persistent connections
+
+ NewRequest = handle_cookies(generate_request_id(Request), State),
+ NewHeaders =
+ (NewRequest#request.headers)#http_request_h{connection
+ = "close"},
+ start_handler(NewRequest#request{headers = NewHeaders}, State),
+ {reply, {ok, NewRequest#request.id}, State};
+
+handle_request(Request, State = #state{options = Options}) ->
+
+ NewRequest = handle_cookies(generate_request_id(Request), State),
+ SessionType = session_type(Options),
+ case select_session(Request#request.method,
+ Request#request.address,
+ Request#request.scheme, SessionType, State) of
{ok, HandlerPid} ->
- pipeline_or_keep_alive(Request1, HandlerPid, State);
+ pipeline_or_keep_alive(NewRequest, HandlerPid, State);
no_connection ->
- create_handler_starter(Request1, State);
- {no_session, OpenSessions}
- when OpenSessions < Opts#options.max_sessions ->
- create_handler_starter(Request1, State);
+ start_handler(NewRequest, State);
+ {no_session, OpenSessions} when OpenSessions
+ < Options#options.max_sessions ->
+ start_handler(NewRequest, State);
{no_session, _} ->
%% Do not start any more persistent connections
%% towards this server.
- Hdrs0 = Request1#request.headers,
- Hdrs1 = Hdrs0#http_request_h{connection = "close"},
- Request2 = Request1#request{headers = Hdrs1},
- create_handler_starter(Request2, State)
+ NewHeaders =
+ (NewRequest#request.headers)#http_request_h{connection
+ = "close"},
+ start_handler(NewRequest#request{headers = NewHeaders}, State)
end,
- {ok, Request1#request.id, State}.
+ {reply, {ok, NewRequest#request.id}, State}.
+
+
+start_handler(Request, State) ->
+ {ok, Pid} =
+ case is_inets_manager() of
+ true ->
+ httpc_handler_sup:start_child([whereis(httpc_handler_sup),
+ Request, State#state.options,
+ State#state.profile_name]);
+ false ->
+ httpc_handler:start_link(self(), Request, State#state.options,
+ State#state.profile_name)
+ end,
+ ets:insert(State#state.handler_db, {Request#request.id,
+ Pid, Request#request.from}),
+ erlang:monitor(process, Pid).
select_session(Method, HostPort, Scheme, SessionType,
#state{options = #options{max_pipeline_length = MaxPipe,
max_keep_alive_length = MaxKeepAlive},
session_db = SessionDb}) ->
- ?hcrd("select session", [{session_type, SessionType},
- {max_pipeline_length, MaxPipe},
+ ?hcrd("select session", [{session_type, SessionType},
+ {max_pipeline_length, MaxPipe},
{max_keep_alive_length, MaxKeepAlive}]),
case httpc_request:is_idempotent(Method) orelse
(SessionType =:= keep_alive) of
@@ -918,92 +709,17 @@ select_session(Candidates, Max) ->
?hcrd("select session - found one", [{handler, HandlerPid}]),
{ok, HandlerPid}
end.
-
-pipeline_or_keep_alive(#request{id = Id} = Request, HandlerPid, State) ->
- ?hcrd("pipeline of keep-alive", [{id, Id}, {handler, HandlerPid}]),
+
+pipeline_or_keep_alive(Request, HandlerPid, State) ->
case (catch httpc_handler:send(Request, HandlerPid)) of
ok ->
- ?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 or keep-alive - failed sending -> "
- "start a new handler", []),
- create_handler_starter(Request, State)
+ ets:insert(State#state.handler_db, {Request#request.id,
+ HandlerPid,
+ Request#request.from});
+ _ -> %timeout pipelining failed
+ start_handler(Request, State)
end.
-
-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) ->
- ?hcrv("create handler starter", [{id, Id}, {profile, ProfileName}]),
- IsInetsManager = is_inets_manager(),
- ManagerPid = self(),
- StarterFun =
- fun() ->
- ?hcrd("handler starter - start",
- [{id, Id},
- {profile, ProfileName},
- {inets_manager, IsInetsManager}]),
- Result1 =
- case IsInetsManager of
- true ->
- httpc_handler_sup:start_child(Options,
- ProfileName);
- false ->
- httpc_handler:start_link(Options,
- ProfileName)
- end,
- ?hcrd("handler starter - maybe connect and send",
- [{id, Id}, {profile, ProfileName}, {result, Result1}]),
- case Result1 of
- {ok, HandlerPid} ->
- StartedMessage =
- {started, self(), Id, HandlerPid},
- ManagerPid ! StartedMessage,
- Result2 = httpc_handler:connect_and_send(Request,
- HandlerPid),
- ?hcrd("handler starter - connected and sent",
- [{id, Id}, {profile, ProfileName},
- {handler, HandlerPid}, {result, Result2}]),
- ConnAndSendMessage =
- {connect_and_send,
- self(), Id, HandlerPid, Result2},
- ManagerPid ! ConnAndSendMessage;
- {error, Reason} ->
- StartFailureMessage =
- {failed_starting_handler, self(), Id, Reason},
- ManagerPid ! StartFailureMessage;
- _ ->
- StartFailureMessage =
- {failed_starting_handler, self(), Id, Result1},
- ManagerPid ! StartFailureMessage
- end
- end,
- Starter = erlang:spawn_link(StarterFun),
- ?hcrd("create handler starter - started", [{id, Id}, {starter, Starter}]),
- Entry = #handler_info{id = Id,
- starter = Starter,
- from = From,
- state = initiating},
- ets:insert(HandlerDb, Entry),
- ok.
-
-
is_inets_manager() ->
case get('$ancestors') of
[httpc_profile_sup | _] ->
@@ -1045,8 +761,6 @@ do_store_cookies([Cookie | Cookies], #state{cookie_db = CookieDb} = State) ->
ok = httpc_cookie:insert(CookieDb, Cookie),
do_store_cookies(Cookies, State).
-
-
session_db_name(ProfileName) ->
make_db_name(ProfileName, "__session_db").
@@ -1074,7 +788,6 @@ cast(ProfileName, Msg) ->
gen_server:cast(ProfileName, Msg).
-
get_proxy(Opts, #options{proxy = Default}) ->
proplists:get_value(proxy, Opts, Default).
@@ -1133,20 +846,6 @@ handle_verbose(trace) ->
handle_verbose(_) ->
ok.
-
error_report(Profile, F, A) ->
Report = io_lib:format("HTTPC-MANAGER<~p> " ++ F ++ "~n", [Profile | A]),
error_logger:error_report(Report).
-
-
-%% d(F) ->
-%% d(F, []).
-
-%% d(F, A) ->
-%% d(get(dbg), F, A).
-
-%% d(true, F, A) ->
-%% io:format(user, "~w:~w:" ++ F ++ "~n", [self(), ?MODULE | A]);
-%% d(_, _, _) ->
-%% ok.
-
diff --git a/lib/inets/src/http_client/httpc_request.erl b/lib/inets/src/http_client/httpc_request.erl
index 0d602adb11..879053f0f2 100644
--- a/lib/inets/src/http_client/httpc_request.erl
+++ b/lib/inets/src/http_client/httpc_request.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -120,7 +120,7 @@ do_send_body(SocketType, Socket, Method, Uri, Version, Headers, Body) ->
version(Version), ?CRLF,
headers(Headers, Version), ?CRLF, Body],
?hcrd("send", [{message, Message}]),
- http_transport:send(SocketType, Socket, lists:append(Message)).
+ http_transport:send(SocketType, Socket, Message).
do_send_body(SocketType, Socket, ProcessBody, Acc) ->
@@ -128,9 +128,7 @@ do_send_body(SocketType, Socket, ProcessBody, Acc) ->
eof ->
ok;
{ok, Data, NewAcc} ->
- DataBin = iolist_to_binary(Data),
- ?hcrd("send", [{data, DataBin}]),
- case http_transport:send(SocketType, Socket, DataBin) of
+ case http_transport:send(SocketType, Socket, Data) of
ok ->
do_send_body(SocketType, Socket, ProcessBody, NewAcc);
Error ->
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index 0a590c9c36..91fb064eec 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -20,38 +20,12 @@
[
{"5.5.2",
[
- {load_module, ftp, soft_purge, soft_purge, []},
- {load_module, http_util, soft_purge, soft_purge, []},
- {load_module, http_transport, soft_purge, soft_purge, []},
- {load_module, httpd_util, soft_purge, soft_purge, [http_util]},
- {load_module, httpd_conf, soft_purge, soft_purge, []},
- {load_module, httpd_file, soft_purge, soft_purge, []},
- {load_module, httpd_log, soft_purge, soft_purge, []},
- {load_module, mod_esi, soft_purge, soft_purge, []},
- {load_module, httpc, soft_purge, soft_purge, [httpc_handler]},
- {load_module, httpc_request, soft_purge, soft_purge, []},
- {update, httpd_sup, soft, soft_purge, soft_purge, [http_transport]},
- {update, httpd_request_handler, soft, soft_purge, soft_purge, []},
- {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_request]}
+ {restart_application, inets}
]
},
{"5.5.1",
[
- {load_module, ftp, soft_purge, soft_purge, []},
- {load_module, http_chunk, soft_purge, soft_purge, []},
- {load_module, http_util, soft_purge, soft_purge, []},
- {load_module, http_transport, soft_purge, soft_purge, []},
- {load_module, httpd_util, soft_purge, soft_purge, [http_util]},
- {load_module, httpd_conf, soft_purge, soft_purge, []},
- {load_module, httpd_file, soft_purge, soft_purge, []},
- {load_module, httpd_log, soft_purge, soft_purge, []},
- {load_module, mod_esi, soft_purge, soft_purge, []},
- {load_module, httpc, soft_purge, soft_purge, [httpc_handler]},
- {load_module, httpc_request, soft_purge, soft_purge, []},
- {update, httpd_sup, soft, soft_purge, soft_purge, [http_transport]},
- {update, httpd_request_handler, soft, soft_purge, soft_purge, []},
- {update, httpc_handler, soft, soft_purge, soft_purge,
- [httpc_request, http_chunk]}
+ {restart_application, inets}
]
},
{"5.5",
@@ -68,38 +42,12 @@
[
{"5.5.2",
[
- {load_module, ftp, soft_purge, soft_purge, []},
- {load_module, http_util, soft_purge, soft_purge, []},
- {load_module, http_transport, soft_purge, soft_purge, []},
- {load_module, httpd_util, soft_purge, soft_purge, [http_util]},
- {load_module, httpd_conf, soft_purge, soft_purge, []},
- {load_module, httpd_file, soft_purge, soft_purge, []},
- {load_module, httpd_log, soft_purge, soft_purge, []},
- {load_module, mod_esi, soft_purge, soft_purge, []},
- {load_module, httpc, soft_purge, soft_purge, [httpc_handler]},
- {load_module, httpc_request, soft_purge, soft_purge, []},
- {update, httpd_sup, soft, soft_purge, soft_purge, [http_transport]},
- {update, httpd_request_handler, soft, soft_purge, soft_purge, []},
- {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_request]}
+ {restart_application, inets}
]
},
{"5.5.1",
[
- {load_module, ftp, soft_purge, soft_purge, []},
- {load_module, http_chunk, soft_purge, soft_purge, []},
- {load_module, http_util, soft_purge, soft_purge, []},
- {load_module, http_transport, soft_purge, soft_purge, []},
- {load_module, httpd_util, soft_purge, soft_purge, [http_util]},
- {load_module, httpd_conf, soft_purge, soft_purge, []},
- {load_module, httpd_file, soft_purge, soft_purge, []},
- {load_module, httpd_log, soft_purge, soft_purge, []},
- {load_module, mod_esi, soft_purge, soft_purge, []},
- {load_module, httpc, soft_purge, soft_purge, [httpc_handler]},
- {load_module, httpc_request, soft_purge, soft_purge, []},
- {update, httpd_sup, soft, soft_purge, soft_purge, [http_transport]},
- {update, httpd_request_handler, soft, soft_purge, soft_purge, []},
- {update, httpc_handler, soft, soft_purge, soft_purge,
- [httpc_request, http_chunk]}
+ {restart_application, inets}
]
},
{"5.5",
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 81e9c2b230..7607bc9eb6 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -115,7 +115,8 @@ all() ->
options,
ipv6,
headers_as_is,
- {group, tickets}
+ {group, tickets},
+ initial_server_connect
].
groups() ->
@@ -140,6 +141,7 @@ groups() ->
otp_8106_fun,
otp_8106_mfa]}].
+
init_per_group(_GroupName, Config) ->
Config.
@@ -199,7 +201,6 @@ end_per_suite(Config) ->
application:stop(ssl),
ok.
-
%%--------------------------------------------------------------------
%% Function: init_per_testcase(Case, Config) -> Config
%% Case - atom()
@@ -214,6 +215,15 @@ end_per_suite(Config) ->
%%--------------------------------------------------------------------
init_per_testcase(otp_8154_1 = Case, Config) ->
init_per_testcase(Case, 5, Config);
+
+init_per_testcase(initial_server_connect, Config) ->
+ inets:start(),
+ application:start(crypto),
+ application:start(public_key),
+ application:start(ssl),
+ application:start(inets),
+ Config;
+
init_per_testcase(Case, Config) ->
init_per_testcase(Case, 2, Config).
@@ -601,34 +611,35 @@ http_inets_pipe(Config) when is_list(Config) ->
{skip, "Failed to start local http-server"}
end.
+
test_pipeline(URL) ->
- p("test_pipeline -> entry with"
- "~n URL: ~p", [URL]),
+ p("test_pipeline -> entry with"
+ "~n URL: ~p", [URL]),
- httpc:set_options([{pipeline_timeout, 50000}]),
-
- p("test_pipeline -> issue (async) request 1"),
- {ok, RequestId1} =
+ httpc:set_options([{pipeline_timeout, 50000}]),
+
+ p("test_pipeline -> issue (async) request 1"),
+ {ok, RequestId1} =
httpc:request(get, {URL, []}, [], [{sync, false}]),
- test_server:format("RequestId1: ~p~n", [RequestId1]),
- p("test_pipeline -> RequestId1: ~p", [RequestId1]),
+ test_server:format("RequestId1: ~p~n", [RequestId1]),
+ p("test_pipeline -> RequestId1: ~p", [RequestId1]),
- %% Make sure pipeline is initiated
- p("test_pipeline -> sleep some", []),
- test_server:sleep(4000),
+ %% Make sure pipeline is initiated
+ p("test_pipeline -> sleep some", []),
+ test_server:sleep(4000),
- p("test_pipeline -> issue (async) request 2"),
- {ok, RequestId2} =
+ p("test_pipeline -> issue (async) request 2"),
+ {ok, RequestId2} =
httpc:request(get, {URL, []}, [], [{sync, false}]),
- tsp("RequestId2: ~p", [RequestId2]),
- p("test_pipeline -> RequestId2: ~p", [RequestId2]),
+ tsp("RequestId2: ~p", [RequestId2]),
+ p("test_pipeline -> RequestId2: ~p", [RequestId2]),
- p("test_pipeline -> issue (sync) request 3"),
- {ok, {{_,200,_}, [_ | _], [_ | _]}} =
+ p("test_pipeline -> issue (sync) request 3"),
+ {ok, {{_,200,_}, [_ | _], [_ | _]}} =
httpc:request(get, {URL, []}, [], []),
p("test_pipeline -> expect reply for (async) request 1 or 2"),
- receive
+ receive
{http, {RequestId1, {{_, 200, _}, _, _}}} ->
p("test_pipeline -> received reply for (async) request 1 - now wait for 2"),
receive
@@ -646,46 +657,46 @@ test_pipeline(URL) ->
ok;
{http, Msg2} ->
test_server:fail(Msg2)
- end;
+ end;
{http, Msg3} ->
test_server:fail(Msg3)
- after 60000 ->
- receive Any1 ->
- tsp("received crap after timeout: ~n ~p", [Any1]),
- test_server:fail({error, {timeout, Any1}})
- end
+ after 60000 ->
+ receive Any1 ->
+ tsp("received crap after timeout: ~n ~p", [Any1]),
+ test_server:fail({error, {timeout, Any1}})
+ end
end,
-
- p("test_pipeline -> sleep some"),
- test_server:sleep(4000),
- p("test_pipeline -> issue (async) request 4"),
- {ok, RequestId3} =
- httpc:request(get, {URL, []}, [], [{sync, false}]),
- tsp("RequestId3: ~p", [RequestId3]),
- p("test_pipeline -> RequestId3: ~p", [RequestId3]),
+ p("test_pipeline -> sleep some"),
+ test_server:sleep(4000),
- p("test_pipeline -> issue (async) request 5"),
- {ok, RequestId4} =
+ p("test_pipeline -> issue (async) request 4"),
+ {ok, RequestId3} =
httpc:request(get, {URL, []}, [], [{sync, false}]),
- tsp("RequestId4: ~p~n", [RequestId4]),
- p("test_pipeline -> RequestId4: ~p", [RequestId4]),
-
- p("test_pipeline -> cancel (async) request 4"),
- ok = httpc:cancel_request(RequestId3),
-
- p("test_pipeline -> expect *no* reply for cancelled (async) request 4 (for 3 secs)"),
- receive
- {http, {RequestId3, _}} ->
- test_server:fail(http_cancel_request_failed)
- after 3000 ->
- ok
- end,
+ tsp("RequestId3: ~p", [RequestId3]),
+ p("test_pipeline -> RequestId3: ~p", [RequestId3]),
- p("test_pipeline -> expect reply for (async) request 4"),
- Body =
- receive
- {http, {RequestId4, {{_, 200, _}, _, BinBody4}}} = Res ->
+ p("test_pipeline -> issue (async) request 5"),
+ {ok, RequestId4} =
+ httpc:request(get, {URL, []}, [], [{sync, false}]),
+ tsp("RequestId4: ~p~n", [RequestId4]),
+ p("test_pipeline -> RequestId4: ~p", [RequestId4]),
+
+ p("test_pipeline -> cancel (async) request 4"),
+ ok = httpc:cancel_request(RequestId3),
+
+ p("test_pipeline -> expect *no* reply for cancelled (async) request 4 (for 3 secs)"),
+ receive
+ {http, {RequestId3, _}} ->
+ test_server:fail(http_cancel_request_failed)
+ after 3000 ->
+ ok
+ end,
+
+ p("test_pipeline -> expect reply for (async) request 4"),
+ Body =
+ receive
+ {http, {RequestId4, {{_, 200, _}, _, BinBody4}}} = Res ->
p("test_pipeline -> received reply for (async) request 5"),
tsp("Receive : ~p", [Res]),
BinBody4;
@@ -700,9 +711,9 @@ test_pipeline(URL) ->
p("test_pipeline -> check reply for (async) request 5"),
inets_test_lib:check_body(binary_to_list(Body)),
-
+
p("test_pipeline -> ensure no unexpected incomming"),
- receive
+ receive
{http, Any} ->
test_server:fail({unexpected_message, Any})
after 500 ->
@@ -712,8 +723,6 @@ test_pipeline(URL) ->
p("test_pipeline -> done"),
ok.
-
-
%%-------------------------------------------------------------------------
http_trace(doc) ->
["Perform a TRACE request that goes through a proxy."];
@@ -1675,25 +1684,11 @@ proxy_https_not_supported(suite) ->
proxy_https_not_supported(Config) when is_list(Config) ->
Result = httpc:request(get, {"https://login.yahoo.com", []}, [], []),
case Result of
- {error, Reason} ->
- %% ok so far
- case Reason of
- {failed_connecting, Why} ->
- %% ok, now check why
- case Why of
- https_through_proxy_is_not_currently_supported ->
- ok;
- _ ->
- tsf({unexpected_why, Why})
- end;
- _ ->
- tsf({unexpected_reason, Reason})
- end;
+ {error, https_through_proxy_is_not_currently_supported} ->
+ ok;
_ ->
- tsf({unexpected_result, Result})
- end,
- ok.
-
+ tsf({unexpected_reason, Result})
+ end.
%%-------------------------------------------------------------------------
@@ -2446,7 +2441,7 @@ otp_8106_fun(Config) when is_list(Config) ->
ok;
_ ->
{skip, "Failed to start local http-server"}
- end.
+ end.
otp_8106_mfa(doc) ->
@@ -2672,7 +2667,7 @@ otp_8739(Config) when is_list(Config) ->
Request = {URL, []},
HttpOptions = [{connect_timeout, 500}, {timeout, 1}],
Options = [{sync, true}],
- case http:request(Method, Request, HttpOptions, Options) of
+ case httpc:request(Method, Request, HttpOptions, Options) of
{error, timeout} ->
%% And now we check the size of the handler db
Info = httpc:info(),
@@ -2729,7 +2724,31 @@ otp_8739_dummy_server_main(_Parent, ListenSocket) ->
exit(Error)
end.
-
+%%-------------------------------------------------------------------------
+
+initial_server_connect(doc) ->
+ ["If this test cases times out the init of httpc_handler process is"
+ "blocking the manager/client process (implementation dependent which) but nither"
+ "should be blocked."];
+initial_server_connect(suite) ->
+ [];
+initial_server_connect(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ ok = httpc:set_options([{ipfamily, inet}]),
+
+ CertFile = filename:join(DataDir, "ssl_server_cert.pem"),
+ SSLOptions = [{certfile, CertFile}, {keyfile, CertFile}],
+
+ {DummyServerPid, Port} = dummy_ssl_server_hang(self(), ipv4, SSLOptions),
+
+ URL = ?SSL_URL_START ++ integer_to_list(Port) ++ "/index.html",
+
+ httpc:request(get, {URL, []}, [{ssl,{essl,[]}}], [{sync, false}]),
+
+ [{session_cookies,[]}] = httpc:which_cookies(),
+
+ DummyServerPid ! stop,
+ ok = httpc:set_options([{ipfamily, inet6fb4}]).
%%--------------------------------------------------------------------
%% Internal functions
@@ -3242,11 +3261,9 @@ pick_header(Headers, Name) ->
Val
end.
-
not_implemented_yet() ->
exit(not_implemented_yet).
-
p(F) ->
p(F, []).
@@ -3260,3 +3277,37 @@ tsp(F, A) ->
tsf(Reason) ->
test_server:fail(Reason).
+
+
+dummy_ssl_server_hang(Caller, IpV, SslOpt) ->
+ Pid = spawn(httpc_SUITE, dummy_ssl_server_hang_init, [Caller, IpV, SslOpt]),
+ receive
+ {port, Port} ->
+ {Pid, Port}
+ end.
+
+dummy_ssl_server_hang_init(Caller, IpV, SslOpt) ->
+ {ok, ListenSocket} =
+ case IpV of
+ ipv4 ->
+ ssl:listen(0, [binary, inet, {packet, 0},
+ {reuseaddr,true},
+ {active, false}] ++ SslOpt);
+ ipv6 ->
+ ssl:listen(0, [binary, inet6, {packet, 0},
+ {reuseaddr,true},
+ {active, false}] ++ SslOpt)
+ end,
+ {ok, {_,Port}} = ssl:sockname(ListenSocket),
+ tsp("dummy_ssl_server_hang_init -> Port: ~p", [Port]),
+ Caller ! {port, Port},
+ {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
+ dummy_ssl_server_hang_loop(AcceptSocket).
+
+dummy_ssl_server_hang_loop(_) ->
+ %% Do not do ssl:ssl_accept as we
+ %% want to time out the underlying gen_tcp:connect
+ receive
+ stop ->
+ ok
+ end.
--
cgit v1.2.3
From 416668b76a84d39855b8d78b84838b8a80f40db9 Mon Sep 17 00:00:00 2001
From: Micael Karlberg
Date: Wed, 11 May 2011 16:55:21 +0200
Subject: Also updated release notes.
---
lib/inets/doc/src/notes.xml | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index b885bcbcdb..edb994a91b 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -104,6 +104,18 @@
*** POTENTIAL INCOMPATIBILITY ***
+ -
+
[httpc] httpc manager crashes.
+ When a request results in a retry, the request id will be "reused"
+ in the previous implementation a race condition could occur causing
+ the manager to crash.
+ This is now avoided by using proc_lib:init_ack and
+ gen_server:enter_loop to allow mor advanced initialization of
+ httpc_handlers without blocking the httpc_manger and eliminating
+ extra processes that can cause race conditions.
+ Own Id: OTP-9246
+
+
--
cgit v1.2.3
From d3d5b4fcf3e07c22e61c2c9a410d365178b12945 Mon Sep 17 00:00:00 2001
From: Micael Karlberg
Date: Thu, 12 May 2011 14:06:12 +0200
Subject: Calling gen_tcp:connect with option {ip, {127,0,0,1}} results in an
exit with reason badarg. Neither SSL nor INETS catches this, resulting in
crashes with incomprehensible reasons.
OTP-9289
---
lib/inets/doc/src/notes.xml | 37 +++++++++++++++++++++----------
lib/inets/src/http_lib/http_transport.erl | 30 ++++++++++++++++++++++---
lib/inets/src/inets_app/inets.appup.src | 8 +++----
lib/ssl/src/ssl.erl | 4 +++-
lib/ssl/vsn.mk | 2 +-
5 files changed, 60 insertions(+), 21 deletions(-)
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index edb994a91b..0926df8581 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -104,18 +104,6 @@
*** POTENTIAL INCOMPATIBILITY ***
- -
-
[httpc] httpc manager crashes.
- When a request results in a retry, the request id will be "reused"
- in the previous implementation a race condition could occur causing
- the manager to crash.
- This is now avoided by using proc_lib:init_ack and
- gen_server:enter_loop to allow mor advanced initialization of
- httpc_handlers without blocking the httpc_manger and eliminating
- extra processes that can cause race conditions.
- Own Id: OTP-9246
-
-
@@ -147,6 +135,31 @@
Bernard Duggan
Own Id: OTP-9158
+
+ -
+
[httpc] httpc manager crashes.
+ When a request results in a retry, the request id will be "reused"
+ in the previous implementation a race condition could occur causing
+ the manager to crash.
+ This is now avoided by using proc_lib:init_ack and
+ gen_server:enter_loop to allow mor advanced initialization of
+ httpc_handlers without blocking the httpc_manger and eliminating
+ extra processes that can cause race conditions.
+ Own Id: OTP-9246
+
+
+ -
+
[httpc] Issuing a request (httpc:request) to an
+ host with the ssl option
+ {ip, {127,0,0,1}} results in an handler crash.
+ The reason was that the connect call resulted in an exit with
+ reason badarg
+ (this was the same for both ssl and gen_tcp).
+ Exits was not catched. This has now been improved.
+ Own Id: OTP-9289
+ Aux Id: seq11845
+
+
diff --git a/lib/inets/src/http_lib/http_transport.erl b/lib/inets/src/http_lib/http_transport.erl
index 173911b868..8cabfe3c71 100644
--- a/lib/inets/src/http_lib/http_transport.erl
+++ b/lib/inets/src/http_lib/http_transport.erl
@@ -110,7 +110,17 @@ connect(ip_comm = _SocketType, {Host, Port}, Opts0, Timeout)
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);
+ try gen_tcp:connect(Host, Port, Opts, Timeout) of
+ {ok, _} = OK ->
+ OK;
+ {error, _} = ERROR ->
+ ERROR
+ catch
+ exit:{badarg, _} ->
+ {error, {eoptions, Opts}};
+ exit:badarg ->
+ {error, {eoptions, Opts}}
+ end;
%% Wrapper for backaward compatibillity
connect({ssl, SslConfig}, Address, Opts, Timeout) ->
@@ -123,7 +133,14 @@ connect({ossl, SslConfig}, {Host, Port}, _, Timeout) ->
{port, Port},
{ssl_config, SslConfig},
{timeout, Timeout}]),
- ssl:connect(Host, Port, Opts, Timeout);
+ case (catch ssl:connect(Host, Port, Opts, Timeout)) of
+ {'EXIT', Reason} ->
+ {error, {eoptions, Reason}};
+ {ok, _} = OK ->
+ OK;
+ {error, _} = ERROR ->
+ ERROR
+ end;
connect({essl, SslConfig}, {Host, Port}, _, Timeout) ->
Opts = [binary, {active, false}, {ssl_imp, new}] ++ SslConfig,
@@ -132,7 +149,14 @@ connect({essl, SslConfig}, {Host, Port}, _, Timeout) ->
{port, Port},
{ssl_config, SslConfig},
{timeout, Timeout}]),
- ssl:connect(Host, Port, Opts, Timeout).
+ case (catch ssl:connect(Host, Port, Opts, Timeout)) of
+ {'EXIT', Reason} ->
+ {error, {eoptions, Reason}};
+ {ok, _} = OK ->
+ OK;
+ {error, _} = ERROR ->
+ ERROR
+ end.
%%-------------------------------------------------------------------------
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index 91fb064eec..47f3fbba58 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -20,12 +20,12 @@
[
{"5.5.2",
[
- {restart_application, inets}
+ {restart_application, inets}
]
},
{"5.5.1",
[
- {restart_application, inets}
+ {restart_application, inets}
]
},
{"5.5",
@@ -42,12 +42,12 @@
[
{"5.5.2",
[
- {restart_application, inets}
+ {restart_application, inets}
]
},
{"5.5.1",
[
- {restart_application, inets}
+ {restart_application, inets}
]
},
{"5.5",
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 7b1fda4cf9..38877ece7e 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -612,8 +612,10 @@ do_new_connect(Address, Port,
catch
exit:{function_clause, _} ->
{error, {eoptions, {cb_info, CbInfo}}};
+ exit:badarg ->
+ {error, {eoptions, {inet_options, UserOpts}}};
exit:{badarg, _} ->
- {error,{eoptions, {inet_options, UserOpts}}}
+ {error, {eoptions, {inet_options, UserOpts}}}
end.
old_connect(Address, Port, Options, Timeout) ->
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index 2f1edfa186..0e80e42637 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1 +1 @@
-SSL_VSN = 4.1.4
+SSL_VSN = 4.1.5
--
cgit v1.2.3
From 30919cea3c641148389a46e94af20805e55f684c Mon Sep 17 00:00:00 2001
From: Micael Karlberg
Date: Thu, 12 May 2011 14:15:37 +0200
Subject: Calling gen_tcp:connect with option {ip, {127,0,0,1}} results in an
exit with reason badarg. Neither SSL nor INETS catches this, resulting in
crashes with incomprehensible reasons.
OTP-9289
---
lib/ssl/doc/src/notes.xml | 84 ++++++++++++++++++++---------------------------
lib/ssl/src/ssl.appup.src | 6 ++--
2 files changed, 40 insertions(+), 50 deletions(-)
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 52ee9c086a..b2d17925fd 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -1,4 +1,4 @@
-
+
@@ -28,59 +28,47 @@
G
notes.xml
- This document describes the changes made to the SSL application.
-
-
- SSL 4.1.4
-
+ This document describes the changes made to the SSL application.
+
+
+ SSL 4.1.5
+
Improvements and New Features
-
- -
-
- Reduced memory footprint of an ssl connection.
-
- Handshake hashes, premaster secret and "public_key_info"
- does not need to be saved when the connection has been
- established. The own certificate is no longer duplicated
- in the state.
-
- Own Id: OTP-9021
-
- -
-
- Add the option {hibernate_after, int()} to ssl:connect
- and ssl:listen
-
- Own Id: OTP-9106
-
-
+
+ -
+
Calling gen_tcp:connect with option {ip, {127,0,0,1}} results in
+ an exit with reason badarg. Neither SSL nor INETS This was not
+ catched, resulting in crashes with incomprehensible reasons.
+ Own Id: OTP-9289 Aux Id: seq11845
+
+
-
-
-
-
+
+
+ SSL 4.1.3
+
Fixed Bugs and Malfunctions
-
- -
-
- Fixed error in cache-handling fix from ssl-4.1.2
-
- Own Id: OTP-9018 Aux Id: seq11739
-
- -
-
- Verification of a critical extended_key_usage-extension
- corrected
-
- Own Id: OTP-9029 Aux Id: seq11541
-
-
+
+ -
+
+ Fixed error in cache-handling fix from ssl-4.1.2
+
+ Own Id: OTP-9018 Aux Id: seq11739
+
+ -
+
Verification of a critical extended_key_usage-extension
+ corrected
+ Own Id: OTP-9029 Aux Id: seq11541
+
+
-
+
-SSL 4.1.2
+
+ SSL 4.1.2
Fixed Bugs and Malfunctions
diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src
index d3e426f254..cf8867245b 100644
--- a/lib/ssl/src/ssl.appup.src
+++ b/lib/ssl/src/ssl.appup.src
@@ -1,17 +1,19 @@
%% -*- erlang -*-
{"%VSN%",
[
+ {"4.1.4", [{restart_application, ssl}]},
{"4.1.3", [{restart_application, ssl}]},
{"4.1.2", [{restart_application, ssl}]},
{"4.1.1", [{restart_application, ssl}]},
- {"4.1", [{restart_application, ssl}]},
+ {"4.1", [{restart_application, ssl}]},
{"4.0.1", [{restart_application, ssl}]}
],
[
+ {"4.1.4", [{restart_application, ssl}]},
{"4.1.3", [{restart_application, ssl}]},
{"4.1.2", [{restart_application, ssl}]},
{"4.1.1", [{restart_application, ssl}]},
- {"4.1", [{restart_application, ssl}]},
+ {"4.1", [{restart_application, ssl}]},
{"4.0.1", [{restart_application, ssl}]}
]}.
--
cgit v1.2.3
From 8c9edd9c00142d0622beb74ef852c79871a631a6 Mon Sep 17 00:00:00 2001
From: Micael Karlberg
Date: Fri, 13 May 2011 15:52:03 +0200
Subject: Fixit init per tescase for testcase for initial_server_connect. For
this case to work, we need crypto!
---
lib/inets/test/httpc_SUITE.erl | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 7607bc9eb6..1998bd3950 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -217,12 +217,17 @@ init_per_testcase(otp_8154_1 = Case, Config) ->
init_per_testcase(Case, 5, Config);
init_per_testcase(initial_server_connect, Config) ->
- inets:start(),
- application:start(crypto),
- application:start(public_key),
- application:start(ssl),
- application:start(inets),
- Config;
+ %% Try to check if crypto actually exist or not,
+ %% this test case does not work unless it does
+ case (catch crypto:start()) of
+ ok ->
+ application:start(public_key),
+ application:start(ssl),
+ inets:start(),
+ Config;
+ _ ->
+ {skip,"Could not start crypto"}
+ end;
init_per_testcase(Case, Config) ->
init_per_testcase(Case, 2, Config).
--
cgit v1.2.3