aboutsummaryrefslogtreecommitdiffstats
path: root/lib/inets
diff options
context:
space:
mode:
Diffstat (limited to 'lib/inets')
-rw-r--r--lib/inets/doc/src/httpc.xml48
-rw-r--r--lib/inets/doc/src/httpd.xml12
-rw-r--r--lib/inets/doc/src/mod_esi.xml29
-rw-r--r--lib/inets/doc/src/mod_security.xml4
-rw-r--r--lib/inets/doc/src/notes.xml82
-rw-r--r--lib/inets/src/ftp/ftp.erl259
-rw-r--r--lib/inets/src/http_client/httpc.erl82
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl18
-rw-r--r--lib/inets/src/http_client/httpc_request.erl102
-rw-r--r--lib/inets/src/http_lib/http_util.erl18
-rw-r--r--lib/inets/src/http_server/httpd_file.erl17
-rw-r--r--lib/inets/src/http_server/httpd_log.erl4
-rw-r--r--lib/inets/src/http_server/httpd_request_handler.erl6
-rw-r--r--lib/inets/src/http_server/httpd_sup.erl2
-rw-r--r--lib/inets/src/http_server/httpd_util.erl38
-rw-r--r--lib/inets/src/http_server/mod_esi.erl8
-rw-r--r--lib/inets/src/inets_app/inets.appup.src56
-rw-r--r--lib/inets/test/ftp_SUITE.erl53
-rw-r--r--lib/inets/test/httpc_SUITE.erl206
-rw-r--r--lib/inets/test/httpd_basic_SUITE.erl56
-rw-r--r--lib/inets/test/httpd_mod.erl5
-rw-r--r--lib/inets/test/inets_app_test.erl14
-rw-r--r--lib/inets/test/inets_test_lib.erl11
-rw-r--r--lib/inets/test/inets_test_lib.hrl2
-rw-r--r--lib/inets/vsn.mk2
25 files changed, 918 insertions, 216 deletions
diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml
index 8f68087871..532f5eefde 100644
--- a/lib/inets/doc/src/httpc.xml
+++ b/lib/inets/doc/src/httpc.xml
@@ -76,21 +76,29 @@ socket_opt() = See the Options used by gen_tcp(3) and
<p>For more information about HTTP see rfc 2616</p>
<code type="none"><![CDATA[
-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()
-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()
]]></code>
</section>
@@ -142,8 +150,9 @@ ssl_options() = {verify, code()} |
<fsummary>Sends a get HTTP-request</fsummary>
<type>
<v>Url = url() </v>
- <v>Result = {status_line(), headers(), body()} |
- {status_code(), body()} | request_id() </v>
+ <v>Result = {status_line(), headers(), Body} |
+ {status_code(), Body} | request_id() </v>
+ <v>Body = string() | binary()</v>
<v>Profile = profile()</v>
<v>Reason = term() </v>
</type>
@@ -191,8 +200,9 @@ ssl_options() = {verify, code()} |
<v>Function = atom() </v>
<v>Args = list() </v>
<v>body_format() = string | binary </v>
- <v>Result = {status_line(), headers(), body()} |
- {status_code(), body()} | request_id() </v>
+ <v>Result = {status_line(), headers(), Body} |
+ {status_code(), Body} | request_id() </v>
+ <v>Body = string() | binary()</v>
<v>Profile = profile() </v>
<v>Reason = {connect_failed, term()} |
{send_failed, term()} | term() </v>
diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml
index 6470b6fac7..ac49a37296 100644
--- a/lib/inets/doc/src/httpd.xml
+++ b/lib/inets/doc/src/httpd.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2010</year>
+ <year>1997</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -794,14 +794,14 @@ bytes
<marker id="sdir_prop"></marker>
<p> Here follows the valid properties for security directories</p>
<taglist>
- <tag>{security_data_file, path()}</tag>
+ <tag>{data_file, path()}</tag>
<item>
Name of the security data file. The filename can either
absolute or relative to the server_root. This file is used to
store persistent data for the mod_security module. </item>
- <tag>{security_max_retries, integer()}</tag>
+ <tag>{max_retries, integer()}</tag>
<item> Specifies the maximum number of tries to authenticate a
user has before the user is blocked out. If a user
@@ -811,13 +811,13 @@ bytes
server will return 401 (Unauthorized), for security
reasons. Defaults to 3 may also be set to infinity.</item>
- <tag>{security_block_time, integer()}</tag>
+ <tag>{block_time, integer()}</tag>
<item> Specifies the number of minutes a user is blocked. After
this amount of time, he automatically regains access.
Defaults to 60</item>
- <tag>{security_fail_expire_time, integer()}</tag>
+ <tag>{fail_expire_time, integer()}</tag>
<item>
Specifies the number of minutes a failed user authentication
@@ -825,7 +825,7 @@ bytes
time, his previous failed authentications are
forgotten. Defaults to 30</item>
- <tag>{security_auth_timeout, integer()}</tag>
+ <tag>{auth_timeout, integer()}</tag>
<item>
Specifies the number of seconds a successful user
diff --git a/lib/inets/doc/src/mod_esi.xml b/lib/inets/doc/src/mod_esi.xml
index e81308a502..9674cd9a88 100644
--- a/lib/inets/doc/src/mod_esi.xml
+++ b/lib/inets/doc/src/mod_esi.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1997</year><year>2010</year>
+ <year>1997</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,16 +32,19 @@
<modulesummary>Erlang Server Interface </modulesummary>
<description>
<p>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.</p>
+ Which is a more efficient way of writing erlang scripts
+ for your Inets web server than writing them as common CGI scripts.</p>
+
+ <marker id="deliver"></marker>
</description>
+
<funcs>
<func>
<name>deliver(SessionID, Data) -> ok | {error, Reason}</name>
<fsummary>Sends Data back to client.</fsummary>
<type>
<v>SessionID = term()</v>
- <v>Data = string() | io_list()</v>
+ <v>Data = string() | io_list() | binary()</v>
<v>Reason = term()</v>
</type>
<desc>
@@ -51,13 +54,15 @@
parts of the content to the user.</p>
<p>Sends data from a Erl Scheme script back to the client.</p>
- <note><p>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
- 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.</p></note>
+ <note>
+ <p>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.</p>
+ </note>
</desc>
</func>
</funcs>
diff --git a/lib/inets/doc/src/mod_security.xml b/lib/inets/doc/src/mod_security.xml
index 2a871d29d8..a3c91dca5b 100644
--- a/lib/inets/doc/src/mod_security.xml
+++ b/lib/inets/doc/src/mod_security.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1998</year><year>2010</year>
+ <year>1998</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 5da9d98002..f9411fed2a 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -32,6 +32,88 @@
<file>notes.xml</file>
</header>
+ <section><title>Inets 5.6</title>
+
+ <section><title>Improvements and New Features</title>
+<!--
+ <p>-</p>
+-->
+ <list>
+ <item>
+ <p>[httpc] Add support for upload body streaming (PUT and POST).</p>
+ <p>For more info,
+ see the definition of the <c>Body</c> argument of the
+ <seealso marker="httpc#request2">request/4,5</seealso>
+ function. </p>
+ <p>Filipe David Manana</p>
+ <p>Own Id: OTP-9094</p>
+ </item>
+
+ <item>
+ <p>[ftp] Added (type) spec for all exported functions.</p>
+ <p>Own Id: OTP-9114 Aux Id: seq11799</p>
+ </item>
+
+ <item>
+ <p>[httpd]
+ <seealso marker="mod_esi#deliver">mod_esi:deliver/2</seealso>
+ made to accept binary data. </p>
+ <p>Bernard Duggan</p>
+ <p>Own Id: OTP-9123</p>
+ </item>
+
+ <item>
+ <p>[httpd] Prevent XSS in error pages.
+ Prevent user controlled input from being interpreted
+ as HTML in error pages by encoding the reserved HTML
+ characters. </p>
+ <p>Michael Santos</p>
+ <p>Own Id: OTP-9124</p>
+ </item>
+
+ <item>
+ <p>[httpd] Improved error messages. </p>
+ <p>Ricardo Catalinas Jim�nez</p>
+ <p>Own Id: OTP-9157</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list>
+ <item>
+ <p>[httpd] Wrong
+ <seealso marker="httpd#sec_prop">security property</seealso>
+ names used in documentation. </p>
+ <p><c>security_data_file</c> used instead of <c>data_file</c>. </p>
+ <p><c>security_max_retries</c> used instead of <c>max_retries</c>. </p>
+ <p><c>security_block_time</c> used instead of <c>block_time</c>. </p>
+ <p><c>security_fail_expire_time</c> used instead of <c>fail_expire_time</c>. </p>
+ <p><c>security_auth_timeout</c> used instead of <c>auth_timeout</c>. </p>
+ <p>Garrett Smith</p>
+ <p>Own Id: OTP-9131</p>
+ </item>
+
+ <item>
+ <p>[httpd] Fix timeout message generated by mod_esi.
+ When a mod_esi request times out, the code to send a
+ timeout response was incorrect and generated an
+ internal server error as well as an invalid response
+ line. </p>
+ <p>Bernard Duggan</p>
+ <p>Own Id: OTP-9158</p>
+ </item>
+ </list>
+ </section>
+
+ </section> <!-- 5.6 -->
+
+
<section><title>Inets 5.5.2</title>
<section><title>Improvements and New Features</title>
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()}.
+
%% <BACKWARD-COMPATIBILLITY>
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()}.
+
%% <BACKWARD-COMPATIBILLITY>
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, <Dir>) -> 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 <LocalFileName>) -> 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 <RemotFileName>) -> 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/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index 04fae13b20..b70b16f57f 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -126,7 +126,10 @@ request(Url, Profile) ->
%% Header = {Field, Value}
%% Field = string()
%% Value = string()
-%% Body = string() | binary() - HTLM-code
+%% Body = string() | binary() | {fun(SendAcc) -> SendFunResult, SendAcc} |
+%% {chunkify, 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
@@ -426,26 +429,44 @@ 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],
+ Started = http_util:timestamp(),
+ NewHeaders0 = [{http_util:to_lower(Key), Val} || {Key, Val} <- Headers0],
try
begin
+ ?hcrt("begin processing", [{started, Started},
+ {new_headers, NewHeaders0}]),
+
+ {NewHeaders, Body} =
+ case Body0 of
+ {chunkify, ProcessBody, Acc}
+ when is_function(ProcessBody, 1) ->
+ NewHeaders1 = ensure_chunked_encoding(NewHeaders0),
+ Body1 = {mk_chunkify_fun(ProcessBody), Acc},
+ {NewHeaders1, Body1};
+ {ProcessBody, _}
+ when is_function(ProcessBody, 1) ->
+ {NewHeaders0, Body0};
+ _ when is_list(Body0) orelse is_binary(Body0) ->
+ {NewHeaders0, Body0};
+ _ ->
+ throw({error, {bad_body, Body0}})
+ end,
+
HTTPOptions = http_options(HTTPOptions0),
Options = request_options(Options0),
Sync = proplists:get_value(sync, Options),
Stream = proplists:get_value(stream, Options),
Host2 = header_host(Scheme, Host, Port),
HeadersRecord = header_record(NewHeaders, Host2, HTTPOptions),
- Receiver = proplists:get_value(receiver, Options),
- SocketOpts = proplists:get_value(socket_opts, Options),
- UrlEncodeBool = HTTPOptions#http_options.url_encode,
- MaybeEscPath = url_encode(Path, UrlEncodeBool),
- MaybeEscQuery = url_encode(Query, UrlEncodeBool),
- AbsUri = url_encode(Url, UrlEncodeBool),
+ Receiver = proplists:get_value(receiver, Options),
+ SocketOpts = proplists:get_value(socket_opts, Options),
+ MaybeEscPath = maybe_encode_uri(HTTPOptions, Path),
+ MaybeEscQuery = maybe_encode_uri(HTTPOptions, Query),
+ AbsUri = maybe_encode_uri(HTTPOptions, Url),
Request = #request{from = Receiver,
scheme = Scheme,
@@ -458,38 +479,71 @@ handle_request(Method, Url,
settings = HTTPOptions,
abs_uri = AbsUri,
userinfo = UserInfo,
- stream = Stream,
- headers_as_is = headers_as_is(Headers, Options),
+ stream = Stream,
+ headers_as_is = headers_as_is(Headers0, Options),
socket_opts = SocketOpts,
started = Started},
+
case httpc_manager:request(Request, profile_name(Profile)) of
{ok, RequestId} ->
handle_answer(RequestId, Sync, Options);
{error, Reason} ->
+ ?hcrd("request failed", [{reason, Reason}]),
{error, Reason}
end
end
catch
error:{noproc, _} ->
+ ?hcrv("noproc", [{profile, Profile}]),
{error, {not_started, Profile}};
throw:Error ->
+ ?hcrv("throw", [{error, Error}]),
Error
end.
-url_encode(URI, true) ->
+ensure_chunked_encoding(Hdrs) ->
+ Key = "transfer-encoding",
+ lists:keystore(Key, 1, Hdrs, {Key, "chunked"}).
+
+maybe_encode_uri(#http_options{url_encode = true}, URI) ->
http_uri:encode(URI);
-url_encode(URI, false) ->
+maybe_encode_uri(_, URI) ->
URI.
+mk_chunkify_fun(ProcessBody) ->
+ fun(eof_body) ->
+ eof;
+ (Acc) ->
+ case ProcessBody(Acc) of
+ eof ->
+ {ok, <<"0\r\n\r\n">>, eof_body};
+ {ok, Data, NewAcc} ->
+ {ok, mk_chunk_bin(Data), NewAcc}
+ end
+ end.
+
+mk_chunk_bin(Data) ->
+ Bin = iolist_to_binary(Data),
+ iolist_to_binary([hex_size(Bin), "\r\n", Bin, "\r\n"]).
+
+hex_size(Bin) ->
+ hd(io_lib:format("~.16B", [size(Bin)])).
+
+
handle_answer(RequestId, false, _) ->
{ok, RequestId};
handle_answer(RequestId, true, Options) ->
receive
{http, {RequestId, saved_to_file}} ->
+ ?hcrt("received saved-to-file", [{request_id, RequestId}]),
{ok, saved_to_file};
{http, {RequestId, {_,_,_} = Result}} ->
+ ?hcrt("received answer", [{request_id, RequestId},
+ {result, Result}]),
return_answer(Options, Result);
{http, {RequestId, {error, Reason}}} ->
+ ?hcrt("received error", [{request_id, RequestId},
+ {reason, Reason}]),
{error, Reason}
end.
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index cb6f3e2841..5e22400fe0 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -1724,9 +1724,27 @@ handle_verbose(_) ->
%% ok.
+send_raw(#session{socket = Socket, socket_type = SocketType},
+ {ProcessBody, Acc}) when is_function(ProcessBody, 1) ->
+ ?hcrt("send raw", [{acc, Acc}]),
+ send_raw(SocketType, Socket, ProcessBody, Acc);
send_raw(#session{socket = Socket, socket_type = SocketType}, Body) ->
http_transport:send(SocketType, Socket, Body).
+send_raw(SocketType, Socket, ProcessBody, Acc) ->
+ case ProcessBody(Acc) of
+ eof ->
+ ok;
+ {ok, Data, NewAcc} ->
+ DataBin = iolist_to_binary(Data),
+ ?hcrd("send", [{data, DataBin}]),
+ case http_transport:send(SocketType, Socket, DataBin) of
+ ok ->
+ send_raw(SocketType, Socket, ProcessBody, NewAcc);
+ Error ->
+ Error
+ end
+ end.
call(Msg, Pid) ->
diff --git a/lib/inets/src/http_client/httpc_request.erl b/lib/inets/src/http_client/httpc_request.erl
index d4df97ad40..0d602adb11 100644
--- a/lib/inets/src/http_client/httpc_request.erl
+++ b/lib/inets/src/http_client/httpc_request.erl
@@ -79,37 +79,65 @@ send(SendAddr, Socket, SocketType,
{settings, HttpOptions},
{userinfo, UserInfo}]),
- TmpHeaders = handle_user_info(UserInfo, Headers),
+ TmpHdrs = handle_user_info(UserInfo, Headers),
- {TmpHeaders2, Body} =
- post_data(Method, TmpHeaders, Content, HeadersAsIs),
+ {TmpHdrs2, Body} = post_data(Method, TmpHdrs, Content, HeadersAsIs),
- {NewHeaders, Uri} = case Address of
- SendAddr ->
- {TmpHeaders2, Path ++ Query};
- _Proxy ->
- TmpHeaders3 =
- handle_proxy(HttpOptions, TmpHeaders2),
- {TmpHeaders3, AbsUri}
- end,
-
- FinalHeaders = case NewHeaders of
- HeaderList when is_list(HeaderList) ->
- http_headers(HeaderList, []);
- _ ->
- http_request:http_headers(NewHeaders)
- end,
+ {NewHeaders, Uri} =
+ case Address of
+ SendAddr ->
+ {TmpHdrs2, Path ++ Query};
+ _Proxy ->
+ TmpHdrs3 = handle_proxy(HttpOptions, TmpHdrs2),
+ {TmpHdrs3, AbsUri}
+ end,
+
+ FinalHeaders =
+ case NewHeaders of
+ HeaderList when is_list(HeaderList) ->
+ http_headers(HeaderList, []);
+ _ ->
+ http_request:http_headers(NewHeaders)
+ 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,
+ {ProcessBody, Acc}) when is_function(ProcessBody, 1) ->
+ ?hcrt("send", [{acc, Acc}]),
+ case do_send_body(SocketType, Socket, Method, Uri, Version, Headers, []) of
+ ok ->
+ do_send_body(SocketType, Socket, ProcessBody, Acc);
+ Error ->
+ Error
+ end;
+do_send_body(SocketType, Socket, Method, Uri, Version, Headers, Body) ->
+ ?hcrt("create message", [{body, 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)).
+do_send_body(SocketType, Socket, ProcessBody, Acc) ->
+ case ProcessBody(Acc) of
+ eof ->
+ ok;
+ {ok, Data, NewAcc} ->
+ DataBin = iolist_to_binary(Data),
+ ?hcrd("send", [{data, DataBin}]),
+ case http_transport:send(SocketType, Socket, DataBin) of
+ ok ->
+ do_send_body(SocketType, Socket, ProcessBody, NewAcc);
+ Error ->
+ Error
+ end
+ end.
+
%%-------------------------------------------------------------------------
%% is_idempotent(Method) ->
@@ -161,7 +189,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 +197,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 +225,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/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_file.erl b/lib/inets/src/http_server/httpd_file.erl
index 7e21d9e158..ccc1f7874a 100644
--- a/lib/inets/src/http_server/httpd_file.erl
+++ b/lib/inets/src/http_server/httpd_file.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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
@@ -26,22 +26,21 @@
handle_error(eacces, Op, ModData, Path) ->
- handle_error(403, Op, ModData, Path,"Forbidden");
+ handle_error(403, Op, ModData, Path, ": Forbidden");
handle_error(enoent, Op, ModData, Path) ->
- handle_error(404, Op, ModData, Path,"File not found");
+ handle_error(404, Op, ModData, Path, ": File not found");
handle_error(enotdir, Op, ModData, Path) ->
handle_error(404, Op, ModData, Path,
- ": A component of the file name is not a directory");
+ ": A component of the file name is not a directory");
handle_error(emfile, Op, _ModData, Path) ->
handle_error(500, Op, none, Path, ": To many open files");
handle_error({enfile,_}, Op, _ModData, Path) ->
handle_error(500, Op, none, Path, ": File table overflow");
handle_error(_Reason, Op, ModData, Path) ->
- handle_error(404, Op, ModData, Path, "File not found").
-
-handle_error(StatusCode, Op, none, Path, Reason) ->
- {StatusCode, none, ?NICE("Can't " ++ Op ++ Path ++ Reason)};
+ handle_error(404, Op, ModData, Path, ": File not found").
+handle_error(StatusCode, Op, none, Path, Reason) ->
+ {StatusCode, none, ?NICE("Can't " ++ Op ++ " " ++ Path ++ Reason)};
handle_error(StatusCode, Op, ModData, Path, Reason) ->
{StatusCode, ModData#mod.request_uri,
- ?NICE("Can't " ++ Op ++ Path ++ Reason)}.
+ ?NICE("Can't " ++ Op ++ " " ++ Path ++ Reason)}.
diff --git a/lib/inets/src/http_server/httpd_log.erl b/lib/inets/src/http_server/httpd_log.erl
index f3ea3aa0e2..db1e2c627a 100644
--- a/lib/inets/src/http_server/httpd_log.erl
+++ b/lib/inets/src/http_server/httpd_log.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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
@@ -113,7 +113,7 @@ do_error_entry(ConfigDB, RemoteHost, undefined, Date, Reason) ->
do_error_entry(ConfigDB, RemoteHost, URI, Date, Reason) ->
case httpd_util:lookup(ConfigDB, error_log_format, pretty) of
pretty ->
- io_lib:format("[~s] access to ~s failed for ~s reason: ~n~p~n",
+ io_lib:format("[~s] access to ~s failed for ~s, reason: ~n~p~n",
[Date, URI, RemoteHost, Reason]);
compact ->
io_lib:format( "[~s] access to ~s failed for ~s, reason: ~w~n",
diff --git a/lib/inets/src/http_server/httpd_request_handler.erl b/lib/inets/src/http_server/httpd_request_handler.erl
index a9db6e2058..c3b47ce390 100644
--- a/lib/inets/src/http_server/httpd_request_handler.erl
+++ b/lib/inets/src/http_server/httpd_request_handler.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
@@ -240,13 +240,13 @@ handle_info({ssl_error, _, _} = Reason, State) ->
%% Timeouts
handle_info(timeout, #state{mod = ModData, mfa = {_, parse, _}} = State) ->
- error_log("No request received on keep-alive connection"
+ error_log("No request received on keep-alive connection "
"before server side timeout", ModData),
%% No response should be sent!
{stop, normal, State#state{response_sent = true}};
handle_info(timeout, #state{mod = ModData} = State) ->
httpd_response:send_status(ModData, 408, "Request timeout"),
- error_log("The client did not send the whole request before the"
+ error_log("The client did not send the whole request before the "
"server side timeout", ModData),
{stop, normal, State#state{response_sent = true}};
diff --git a/lib/inets/src/http_server/httpd_sup.erl b/lib/inets/src/http_server/httpd_sup.erl
index f94e5459c1..b248c9bcf0 100644
--- a/lib/inets/src/http_server/httpd_sup.erl
+++ b/lib/inets/src/http_server/httpd_sup.erl
@@ -90,7 +90,7 @@ id(Address, Port) ->
%%% Supervisor callback
%%%=========================================================================
init([HttpdServices]) ->
- ?hdrd("starting", []),
+ ?hdrd("starting", [{httpd_service, HttpdServices}]),
RestartStrategy = one_for_one,
MaxR = 10,
MaxT = 3600,
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.<P>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/src/http_server/mod_esi.erl b/lib/inets/src/http_server/mod_esi.erl
index 929185a67a..e36c33b282 100644
--- a/lib/inets/src/http_server/mod_esi.erl
+++ b/lib/inets/src/http_server/mod_esi.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
@@ -415,7 +415,7 @@ deliver_webpage_chunk(#mod{config_db = Db} = ModData, Pid, Timeout) ->
end;
timeout ->
?hdrv("deliver_webpage_chunk - timeout", []),
- send_headers(ModData, {504, "Timeout"},[{"connection", "close"}]),
+ send_headers(ModData, 504, [{"connection", "close"}]),
httpd_socket:close(ModData#mod.socket_type, ModData#mod.socket),
process_flag(trap_exit,false),
{proceed,[{response, {already_sent, 200, 0}} | ModData#mod.data]}
@@ -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),
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index 07da8ca961..df18ffa9e8 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -18,9 +18,34 @@
{"%VSN%",
[
+ {"5.5.2",
+ [
+ {load_module, ftp, soft_purge, soft_purge, []},
+ {load_module, http_util, 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_request_handler, soft, soft_purge, soft_purge, []},
+ {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_request]}
+ ]
+ },
{"5.5.1",
[
- {load_module, http_chunk, soft_purge, soft_purge, []}
+ {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, 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_request_handler, soft, soft_purge, soft_purge, []},
+ {update, httpc_handler, soft, soft_purge, soft_purge,
+ [httpc_request, http_chunk]}
]
},
{"5.5",
@@ -34,10 +59,35 @@
]
}
],
- [
+ [
+ {"5.5.2",
+ [
+ {load_module, ftp, soft_purge, soft_purge, []},
+ {load_module, http_util, 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_request_handler, soft, soft_purge, soft_purge, []},
+ {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_request]}
+ ]
+ },
{"5.5.1",
[
- {load_module, http_chunk, soft_purge, soft_purge, []}
+ {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, 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_request_handler, soft, soft_purge, soft_purge, []},
+ {update, httpc_handler, soft, soft_purge, soft_purge,
+ [httpc_request, http_chunk]}
]
},
{"5.5",
diff --git a/lib/inets/test/ftp_SUITE.erl b/lib/inets/test/ftp_SUITE.erl
index 4bafdbfef8..17e5f6777e 100644
--- a/lib/inets/test/ftp_SUITE.erl
+++ b/lib/inets/test/ftp_SUITE.erl
@@ -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/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 2c8febf5ed..81e9c2b230 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -28,6 +28,7 @@
-include("test_server_line.hrl").
-include_lib("kernel/include/file.hrl").
+-include("inets_test_lib.hrl").
%% Note: This directive should only be used in test suites.
-compile(export_all).
@@ -62,36 +63,82 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [proxy_options, proxy_head, proxy_get, proxy_trace,
- proxy_post, proxy_put, proxy_delete, proxy_auth,
- proxy_headers, proxy_emulate_lower_versions,
- http_options, http_head, http_get, http_post,
- http_dummy_pipe, http_inets_pipe, http_trace,
- http_async, http_save_to_file, http_save_to_file_async,
- http_headers, http_headers_dummy, http_bad_response,
- ssl_head, ossl_head, essl_head, ssl_get, ossl_get,
- essl_get, ssl_trace, ossl_trace, essl_trace,
- http_redirect, http_redirect_loop,
- http_internal_server_error, http_userinfo, http_cookie,
- http_server_does_not_exist, http_invalid_http,
- http_emulate_lower_versions, http_relaxed,
- page_does_not_exist, proxy_page_does_not_exist,
- proxy_https_not_supported, http_stream,
- http_stream_once, proxy_stream, parse_url, options,
- ipv6, headers_as_is, {group, tickets}].
+ [
+ proxy_options,
+ proxy_head,
+ proxy_get,
+ proxy_trace,
+ proxy_post,
+ proxy_put,
+ proxy_delete,
+ proxy_auth,
+ proxy_headers,
+ proxy_emulate_lower_versions,
+ http_options,
+ http_head,
+ http_get,
+ http_post,
+ http_post_streaming,
+ http_dummy_pipe,
+ http_inets_pipe,
+ http_trace,
+ http_async,
+ http_save_to_file,
+ http_save_to_file_async,
+ http_headers,
+ http_headers_dummy,
+ http_bad_response,
+ ssl_head,
+ ossl_head,
+ essl_head,
+ ssl_get,
+ ossl_get,
+ essl_get,
+ ssl_trace,
+ ossl_trace,
+ essl_trace,
+ http_redirect,
+ http_redirect_loop,
+ http_internal_server_error,
+ http_userinfo, http_cookie,
+ http_server_does_not_exist,
+ http_invalid_http,
+ http_emulate_lower_versions,
+ http_relaxed,
+ page_does_not_exist,
+ proxy_page_does_not_exist,
+ proxy_https_not_supported,
+ http_stream,
+ http_stream_once,
+ proxy_stream,
+ parse_url,
+ options,
+ ipv6,
+ headers_as_is,
+ {group, tickets}
+ ].
groups() ->
- [{tickets, [],
- [hexed_query_otp_6191, empty_body_otp_6243,
- empty_response_header_otp_6830,
- transfer_encoding_otp_6807, proxy_not_modified_otp_6821,
- no_content_204_otp_6982, missing_CR_otp_7304,
- {group, otp_7883}, {group, otp_8154}, {group, otp_8106},
- otp_8056, otp_8352, otp_8371, otp_8739]},
- {otp_7883, [], [otp_7883_1, otp_7883_2]},
+ [{tickets, [], [hexed_query_otp_6191,
+ empty_body_otp_6243,
+ empty_response_header_otp_6830,
+ transfer_encoding_otp_6807,
+ proxy_not_modified_otp_6821,
+ no_content_204_otp_6982,
+ missing_CR_otp_7304,
+ {group, otp_7883},
+ {group, otp_8154},
+ {group, otp_8106},
+ otp_8056,
+ otp_8352,
+ otp_8371,
+ otp_8739]},
+ {otp_7883, [], [otp_7883_1,
+ otp_7883_2]},
{otp_8154, [], [otp_8154_1]},
- {otp_8106, [],
- [otp_8106_pid, otp_8106_fun, otp_8106_mfa]}].
+ {otp_8106, [], [otp_8106_pid,
+ otp_8106_fun,
+ otp_8106_mfa]}].
init_per_group(_GroupName, Config) ->
Config.
@@ -138,6 +185,7 @@ init_per_suite(Config) ->
{local_port, ?IP_PORT},
{local_ssl_port, ?SSL_PORT} | Config].
+
%%--------------------------------------------------------------------
%% Function: end_per_suite(Config) -> _
%% Config - [tuple()]
@@ -151,6 +199,7 @@ end_per_suite(Config) ->
application:stop(ssl),
ok.
+
%%--------------------------------------------------------------------
%% Function: init_per_testcase(Case, Config) -> Config
%% Case - atom()
@@ -180,8 +229,8 @@ init_per_testcase_ssl(Tag, PrivDir, SslConfFile, Config) ->
[{local_ssl_server, Server} | Config2].
init_per_testcase(Case, Timeout, Config) ->
- io:format(user, "~n~n*** INIT ~w:[~w][~w] ***~n~n",
- [?MODULE, Timeout, Case]),
+ io:format(user, "~n~n*** INIT ~w:~w[~w] ***~n~n",
+ [?MODULE, Case, Timeout]),
PrivDir = ?config(priv_dir, Config),
tsp("init_per_testcase -> stop inets"),
application:stop(inets),
@@ -205,9 +254,10 @@ init_per_testcase(Case, Timeout, Config) ->
[$e, $s, $s, $l | _] ->
init_per_testcase_ssl(essl, PrivDir, SslConfFile, [{watchdog, Dog} | TmpConfig]);
- "proxy" ++ Rest ->
+ "proxy_" ++ Rest ->
+ io:format("init_per_testcase -> Rest: ~p~n", [Rest]),
case Rest of
- "_https_not_supported" ->
+ "https_not_supported" ->
tsp("init_per_testcase -> [proxy case] start inets"),
inets:start(),
tsp("init_per_testcase -> [proxy case] start ssl"),
@@ -221,13 +271,39 @@ init_per_testcase(Case, Timeout, Config) ->
| TmpConfig]
end;
_ ->
+ %% We use erlang.org for the proxy tests
+ %% and after the switch to erlang-web, many
+ %% of the test cases no longer work (erlang.org
+ %% previously run on Apache).
+ %% Until we have had time to update inets
+ %% (and updated erlang.org to use that inets)
+ %% and the test cases, we simply skip the
+ %% problematic test cases.
+ %% This is not ideal, but I am busy....
case is_proxy_available(?PROXY, ?PROXY_PORT) of
true ->
- inets:start(),
- [{watchdog, Dog} | TmpConfig];
+ BadCases =
+ [
+ "delete",
+ "get",
+ "head",
+ "not_modified_otp_6821",
+ "options",
+ "page_does_not_exist",
+ "post",
+ "put",
+ "stream"
+ ],
+ case lists:member(Rest, BadCases) of
+ true ->
+ [{skip, "TC and server not compatible"}|
+ TmpConfig];
+ false ->
+ inets:start(),
+ [{watchdog, Dog} | TmpConfig]
+ end;
false ->
- [{skip, "Failed to contact proxy"} |
- TmpConfig]
+ [{skip, "proxy not responding"} | TmpConfig]
end
end;
_ ->
@@ -395,6 +471,53 @@ http_post(Config) when is_list(Config) ->
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) ->
+ io:format("~w:http_post_streaming_fun -> "
+ "zero~n", [?MODULE]),
+ eof;
+ (LenLeft) ->
+ io:format("~w:http_post_streaming_fun -> "
+ "LenLeft: ~p~n", [?MODULE, 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."];
http_emulate_lower_versions(suite) ->
@@ -1253,6 +1376,9 @@ proxy_options(doc) ->
proxy_options(suite) ->
[];
proxy_options(Config) when is_list(Config) ->
+ %% As of 2011-03-24, erlang.org (which is used as server)
+ %% does no longer run Apache, but instead runs inets, which
+ %% do not implement "options".
case ?config(skip, Config) of
undefined ->
case httpc:request(options, {?PROXY_URL, []}, [], []) of
@@ -1277,6 +1403,8 @@ proxy_head(doc) ->
proxy_head(suite) ->
[];
proxy_head(Config) when is_list(Config) ->
+ %% As of 2011-03-24, erlang.org (which is used as server)
+ %% does no longer run Apache, but instead runs inets.
case ?config(skip, Config) of
undefined ->
case httpc:request(head, {?PROXY_URL, []}, [], []) of
@@ -1372,6 +1500,8 @@ proxy_post(doc) ->
proxy_post(suite) ->
[];
proxy_post(Config) when is_list(Config) ->
+ %% As of 2011-03-24, erlang.org (which is used as server)
+ %% does no longer run Apache, but instead runs inets.
case ?config(skip, Config) of
undefined ->
case httpc:request(post, {?PROXY_URL, [],
@@ -1394,6 +1524,8 @@ proxy_put(doc) ->
proxy_put(suite) ->
[];
proxy_put(Config) when is_list(Config) ->
+ %% As of 2011-03-24, erlang.org (which is used as server)
+ %% does no longer run Apache, but instead runs inets.
case ?config(skip, Config) of
undefined ->
case httpc:request(put, {"http://www.erlang.org/foobar.html", [],
@@ -1418,6 +1550,8 @@ proxy_delete(doc) ->
proxy_delete(suite) ->
[];
proxy_delete(Config) when is_list(Config) ->
+ %% As of 2011-03-24, erlang.org (which is used as server)
+ %% does no longer run Apache, but instead runs inets.
case ?config(skip, Config) of
undefined ->
URL = ?PROXY_URL ++ "/foobar.html",
@@ -2573,7 +2707,7 @@ otp_8739_dummy_server_init(Parent) ->
Parent ! {port, Port},
otp_8739_dummy_server_main(Parent, ListenSocket).
-otp_8739_dummy_server_main(Parent, ListenSocket) ->
+otp_8739_dummy_server_main(_Parent, ListenSocket) ->
case gen_tcp:accept(ListenSocket) of
{ok, Sock} ->
%% Ignore the request, and simply wait for the socket to close
diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl
index 3e29b68283..f23d0b4765 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,22 +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 = "/<b>this_is_bold<b>",
+ _Address = proplists:get_value(bind_address, Info),
+ Path = "/<b>this_is_bold</b>",
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}]),
+ {ok, {404, Body1}} = httpc:request(get, {URL, []},
+ [{url_encode, true},
+ {version, "HTTP/1.0"}],
+ [{full_result, false}]),
EscapedPath = find_URL_path(string:tokens(Body1, " ")),
- inets:stop(httpd, Pid).
+ {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(Body2, " ")),
+ inets:stop(httpd, Pid),
+ tsp("escaped_url_in_error_body -> done"),
+ ok.
find_URL_path([]) ->
"";
@@ -165,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]).
+
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('[email protected]').
-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,
diff --git a/lib/inets/test/inets_app_test.erl b/lib/inets/test/inets_app_test.erl
index 11b507fa26..49ea18501f 100644
--- a/lib/inets/test/inets_app_test.erl
+++ b/lib/inets/test/inets_app_test.erl
@@ -241,6 +241,20 @@ undef_funcs(suite) ->
undef_funcs(doc) ->
[];
undef_funcs(Config) when is_list(Config) ->
+ %% We need to check if there is a point to run this test.
+ %% On some platforms, crypto will not build, which in turn
+ %% causes ssl to not to not build (at this time, this will
+ %% change in the future).
+ %% So, we first check if we can start crypto, and if not,
+ %% we skip this test case!
+ case (catch crypto:start()) of
+ ok ->
+ ok;
+ {error, {already_started, crypto}} ->
+ ok;
+ _ ->
+ ?SKIP(crypto_start_check_failed)
+ end,
App = inets,
AppFile = key1search(app_file, Config),
Mods = key1search(modules, AppFile),
diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl
index c56a714f5a..c837326bb5 100644
--- a/lib/inets/test/inets_test_lib.erl
+++ b/lib/inets/test/inets_test_lib.erl
@@ -32,7 +32,7 @@
-export([check_body/1]).
-export([millis/0, millis_diff/2, hours/1, minutes/1, seconds/1, sleep/1]).
-export([oscmd/1]).
--export([non_pc_tc_maybe_skip/4, os_based_skip/1]).
+-export([non_pc_tc_maybe_skip/4, os_based_skip/1, skip/3, fail/3]).
-export([flush/0]).
-export([start_node/1, stop_node/1]).
@@ -395,6 +395,13 @@ sleep(MSecs) ->
skip(Reason, File, Line) ->
exit({skipped, {Reason, File, Line}}).
+fail(Reason, File, Line) ->
+ String = lists:flatten(io_lib:format("Failure ~p(~p): ~p~n",
+ [File, Line, Reason])),
+ tsf(String).
+
+
+
flush() ->
receive
Msg ->
@@ -407,7 +414,7 @@ flush() ->
tsp(F) ->
tsp(F, []).
tsp(F, A) ->
- test_server:format("~p ~p:" ++ F ++ "~n", [self(), ?MODULE | A]).
+ test_server:format("~p ~p ~p:" ++ F ++ "~n", [node(), self(), ?MODULE | A]).
tsf(Reason) ->
test_server:fail(Reason).
diff --git a/lib/inets/test/inets_test_lib.hrl b/lib/inets/test/inets_test_lib.hrl
index 0cdb04139c..cc83a309b5 100644
--- a/lib/inets/test/inets_test_lib.hrl
+++ b/lib/inets/test/inets_test_lib.hrl
@@ -72,7 +72,7 @@
%% - Test case macros -
--define(SKIP(Reason), inets_test_lib:skip(Reason)).
+-define(SKIP(Reason), inets_test_lib:skip(Reason, ?MODULE, ?LINE)).
-define(FAIL(Reason), inets_test_lib:fail(Reason, ?MODULE, ?LINE)).
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)"