From f555a1b1ed4461c33a99737136daf2793479425e Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 16 Dec 2011 17:52:39 +0100 Subject: [inets/httpd] Add server tokens config option Added ability to configure the server software header field (with the server_tokens config option). OTP-9805 --- lib/inets/doc/src/httpd.xml | 545 +++++++++++++++---------- lib/inets/doc/src/notes.xml | 73 +++- lib/inets/src/http_server/Makefile | 2 + lib/inets/src/http_server/httpd_conf.erl | 106 ++++- lib/inets/src/http_server/httpd_response.erl | 27 +- lib/inets/src/http_server/httpd_script_env.erl | 57 ++- lib/inets/src/inets_app/inets.mk | 2 - lib/inets/vsn.mk | 2 +- 8 files changed, 564 insertions(+), 250 deletions(-) diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml index f88099a82e..7e21229fcf 100644 --- a/lib/inets/doc/src/httpd.xml +++ b/lib/inets/doc/src/httpd.xml @@ -55,14 +55,14 @@
ERLANG HTTP SERVER SERVICE START/STOP

A web server can be configured to start when starting the inets - application or started dynamically in runtime by calling the - Inets application API inets:start(httpd, ServiceConfig), or - inets:start(httpd, ServiceConfig, How), - see inets(3) Below follows a - description of the available configuration options, also called - properties.

- - + application or started dynamically in runtime by calling the + Inets application API inets:start(httpd, ServiceConfig), or + inets:start(httpd, ServiceConfig, How), + see inets(3) Below follows a + description of the available configuration options, also called + properties.

+ +

File properties

When the web server is started @@ -76,21 +76,25 @@ list.

+ {proplist_file, path()} - If this property is defined inets will expect to find - all other properties defined in this file. Note that the - file must include all properties listed under mandatory - properties. - {file, path()} +

If this property is defined inets will expect to find + all other properties defined in this file. Note that the + file must include all properties listed under mandatory + properties.

+ - If this property is defined - inets will expect to find all other properties defined in this - file, that uses Apache like syntax. Note that the file must - include all properties listed under mandatory properties. The - Apache like syntax is the property, written as one word where - each new word begins with a capital, followed by a white-space - followed by the value followed by a new line. Ex: + + {file, path()} + +

If this property is defined inets will expect to find all + other properties defined in this file, that uses Apache like + syntax. Note that the file must include all properties listed + under mandatory properties. The Apache like syntax is the property, + written as one word where each new word begins with a capital, + followed by a white-space followed by the value followed by a + new line. Ex:

{server_root, "/urs/local/www"} -> ServerRoot /usr/local/www @@ -114,40 +118,51 @@

The properties proplist_file and file are mutually exclusive.

- +

Mandatory properties

+ {port, integer()} - The port that the HTTP server shall listen on. - If zero is specified as port, an arbitrary available port - will be picked and you can use the httpd:info/2 function to find - out which port was picked. +

The port that the HTTP server shall listen on. + If zero is specified as port, an arbitrary available port + will be picked and you can use the httpd:info/2 function to find + out which port was picked.

+
+ + {server_name, string()} - The name of your server, normally a fully qualified domain - name. +

The name of your server, normally a fully qualified domain name.

+ + {server_root, path()} - Defines the servers home directory where log files etc can +

Defines the servers home directory where log files etc can be stored. Relative paths specified in other properties refer - to this directory. + to this directory.

+
+ + {document_root, path()} Defines the top directory for the documents that - are available on the HTTP server. + are available on the HTTP server. +
- +

Communication properties

+ {bind_address, ip_address() | hostname() | any} - Defaults to any. Note that any is denoted * - in the apache like configuration file. +

Defaults to any. Note that any is denoted * + in the apache like configuration file.

+ {socket_type, ip_comm | ssl | essl}

When using ssl, there are currently only one alternative. @@ -156,6 +171,7 @@

Defaults to ip_comm.

+ {ipfamily, inet | inet6 | inet6fb4}

Defaults to inet6fb4.

@@ -165,74 +181,93 @@
+

Erlang Web server API modules

+ {modules, [atom()]} - Defines which modules the HTTP server will use to handle +

Defines which modules the HTTP server will use to handle requests. Defaults to: [mod_alias, mod_auth, mod_esi, mod_actions, mod_cgi, mod_dir, mod_get, mod_head, mod_log, mod_disk_log] Note that some mod-modules are dependent on others, so the order can not be entirely arbitrary. See the Inets Web server Modules in the - Users guide for more information. + Users guide for more information.

-
+ - +

Limit properties

+ {disable_chunked_transfer_encoding_send, boolean()} - This property allows you to disable chunked +

This property allows you to disable chunked transfer-encoding when sending a response to a HTTP/1.1 - client, by default this is false. + client, by default this is false.

+
+ {keep_alive, boolean()} - Instructs the server whether or not to use persistent +

Instructs the server whether or not to use persistent connections when the client claims to be HTTP/1.1 - compliant, default is true. + compliant, default is true.

+
+ {keep_alive_timeout, integer()} - The number of seconds the server will wait for a +

The number of seconds the server will wait for a subsequent request from the client before closing the - connection. Default is 150. + connection. Default is 150.

+
+ {max_body_size, integer()} - Limits the size of the message body of HTTP request. - By the default there is no limit. +

Limits the size of the message body of HTTP request. + By the default there is no limit.

+ + {max_clients, integer()} - Limits the number of simultaneous requests that can be - supported. Defaults to 150. +

Limits the number of simultaneous requests that can be + supported. Defaults to 150.

+ + {max_header_size, integer()} - Limits the size of the message header of HTTP request. - Defaults to 10240. +

Limits the size of the message header of HTTP request. + Defaults to 10240.

+ {max_uri, integer()} - Limits the size of the HTTP request URI. By - default there is no limit. +

Limits the size of the HTTP request URI. By + default there is no limit.

+ + {max_keep_alive_requests, integer()} - The number of request that a client can do on one + +

The number of request that a client can do on one connection. When the server has responded to the number of requests defined by max_keep_alive_requests the server close the connection. The server will close it even if there are queued - request. Defaults to no limit. + request. Defaults to no limit.

+
- +

Administrative properties

+ {mime_types, [{MimeType, Extension}] | path()}

Where MimeType = string() and Extension = string(). @@ -250,19 +285,43 @@ text/plain asc txt

Defaults to [{"html","text/html"},{"htm","text/html"}]

+ {mime_type, string()} - - When the server is asked to provide a document type which +

When the server is asked to provide a document type which cannot be determined by the MIME Type Settings, the server will - use this default type. + use this default type.

+
+ {server_admin, string()} - ServerAdmin defines the email-address of the server +

ServerAdmin defines the email-address of the server administrator, to be included in any error messages returned by - the server. + the server.

+
+ + {server_tokens, prod|major|minor|minimal|os|full|{private, string()}} + +

ServerTokens defines how the value of the server header + should look.

+

Example: Assuming the version of inets is 5.8.1, + here is what the server header string could look like for + the different values of server-tokens:

+
+prod                  "inets"
+major                 "inets/5"
+minor                 "inets/5.8"
+minimal               "inets/5.8.1"
+os                    "inets/5.8.1 (unix)"
+full                  "inets/5.8.1 (unix/linux) OTP/R15B"
+{private, "foo/bar"}  "foo/bar"
+	
+

By default, the value is as before, which is minimal.

+
+ + {log_format, common | combined}

Defines if access logs should be written according to the common @@ -307,8 +366,9 @@ bytes

This affects the access logs written by mod_log and mod_disk_log.

-
- + + + {error_log_format, pretty | compact}

Defaults to pretty. If the error log is meant to be read @@ -330,63 +390,77 @@ bytes - +

ssl properties

+ {ssl_ca_certificate_file, path()} - Used as cacertfile option in ssl:listen/2 see - ssl(3) +

Used as cacertfile option in ssl:listen/2 see + ssl(3).

+
+ {ssl_certificate_file, path()} - Used as certfile option in ssl:listen/2 see - ssl(3) +

Used as certfile option in ssl:listen/2 see + ssl(3).

+ {ssl_ciphers, list()} - Used as ciphers option in ssl:listen/2 see - ssl(3) +

Used as ciphers option in ssl:listen/2 see + ssl(3).

+ {ssl_verify_client, integer()} - Used as verify option in ssl:listen/2 see - ssl(3) +

Used as verify option in ssl:listen/2 see + ssl(3).

+ + {ssl_verify_depth, integer()} - Used as depth option in ssl:listen/2 see - ssl(3) +

Used as depth option in ssl:listen/2 see + ssl(3).

+ + {ssl_password_callback_function, atom()} - Used together with ssl_password_callback_module +

Used together with ssl_password_callback_module to retrieve a value to use as password option to ssl:listen/2 - see ssl(3) + see ssl(3).

+ {ssl_password_callback_arguments, list()} - Used together with ssl_password_callback_function to supply a +

Used together with ssl_password_callback_function to supply a list of arguments to the callback function. If not specified - the callback function will be assumed to have arity 0. + the callback function will be assumed to have arity 0.

+
+ {ssl_password_callback_module, atom()} - Used together with ssl_password_callback_function +

Used together with ssl_password_callback_function to retrieve a value to use as password option to ssl:listen/2 - see ssl(3) + see ssl(3).

+
- +

URL aliasing properties - requires mod_alias

+ {alias, {Alias, RealName}} - - Where Alias = string() and RealName = string(). + +

Where Alias = string() and RealName = string(). The Alias property allows documents to be stored in the local file system instead of the document_root location. URLs with a path that begins with url-path is mapped to local files that begins with @@ -395,11 +469,13 @@ bytes {alias, {"/image", "/ftp/pub/image"} and an access to http://your.server.org/image/foo.gif would refer to - the file /ftp/pub/image/foo.gif. + the file /ftp/pub/image/foo.gif.

+
- {re_write, {Re, Replacement}} - - Where Re = string() and Replacement = string(). + + {re_write, {Re, Replacement}} + +

Where Re = string() and Replacement = string(). The ReWrite property allows documents to be stored in the local file system instead of the document_root location. URLs are rewritten by re:replace/3 to produce a path in the local filesystem. @@ -419,13 +495,13 @@ bytes Beware of trailing space in Replacement that will be used. If you must have a space in Re use e.g the character encoding - \040 see re(3). + \040 see re(3).

- {directory_index, [string()]} - + + {directory_index, [string()]} - DirectoryIndex specifies a list of resources to look for +

DirectoryIndex specifies a list of resources to look for if a client requests a directory using a / at the end of the directory name. file depicts the name of a file in the directory. Several files may be given, in which case the server @@ -436,70 +512,79 @@ bytes and access to http://your.server.org/docs/ would return http://your.server.org/docs/index.html or http://your.server.org/docs/welcome.html if index.html do not - exist. + exist.

- +

CGI properties - requires mod_cgi

+ {script_alias, {Alias, RealName}} - Where Alias = string() and RealName = string(). + +

Where Alias = string() and RealName = string(). Has the same behavior as the Alias property, except that it also marks the target directory as containing CGI scripts. URLs with a path beginning with url-path are mapped to scripts beginning with directory-filename, for example: - {script_alias, {"/cgi-bin/", "/web/cgi-bin/"} + {script_alias, {"/cgi-bin/", "/web/cgi-bin/"} and an access to http://your.server.org/cgi-bin/foo would cause - the server to run the script /web/cgi-bin/foo. + the server to run the script /web/cgi-bin/foo.

+ {script_re_write, {Re, Replacement}} - Where Re = string() and Replacement = string(). + +

Where Re = string() and Replacement = string(). Has the same behavior as the ReWrite property, except that it also marks the target directory as containing CGI scripts. URLs with a path beginning with url-path are mapped to scripts beginning with directory-filename, for example: - {script_re_write, {"^/cgi-bin/(\\d+)/", "/web/\\1/cgi-bin/"} + {script_re_write, {"^/cgi-bin/(\\d+)/", "/web/\\1/cgi-bin/"} and an access to http://your.server.org/cgi-bin/17/foo would cause - the server to run the script /web/17/cgi-bin/foo. + the server to run the script /web/17/cgi-bin/foo.

+ {script_nocache, boolean()} - - If ScriptNoCache is set to true the HTTP server will by +

If ScriptNoCache is set to true the HTTP server will by default add the header fields necessary to prevent proxies from caching the page. Generally this is something you want. Defaults - to false. + to false.

+
+ {script_timeout, integer()} - - The time in seconds the web server will wait between each +

The time in seconds the web server will wait between each chunk of data from the script. If the CGI-script not delivers any data before the timeout the connection to the client will be - closed. Defaults to 15. + closed. Defaults to 15.

+
+ {action, {MimeType, CgiScript}} - requires mod_action - - Where MimeType = string() and CgiScript = string(). + +

Where MimeType = string() and CgiScript = string(). Action adds an action, which will activate a cgi-script whenever a file of a certain mime-type is requested. It propagates the URL and file path of the requested document using the standard CGI PATH_INFO and PATH_TRANSLATED environment variables. - {action, {"text/plain", "/cgi-bin/log_and_deliver_text"} - + + {action, {"text/plain", "/cgi-bin/log_and_deliver_text"} +

+ {script, {Method, CgiScript}} - requires mod_action - - Where Method = string() and CgiScript = string(). + +

Where Method = string() and CgiScript = string(). Script adds an action, which will activate a cgi-script whenever a file is requested using a certain HTTP method. The method is either GET or POST as defined in RFC 1945. It @@ -507,18 +592,19 @@ bytes the standard CGI PATH_INFO and PATH_TRANSLATED environment variables. - {script, {"PUT", "/cgi-bin/put"} - + {script, {"PUT", "/cgi-bin/put"} +

- +

ESI properties - requires mod_esi

- {erl_script_alias, {URLPath, [AllowedModule]}} - - Where URLPath = string() and AllowedModule = atom(). + + {erl_script_alias, {URLPath, [AllowedModule]}} + +

Where URLPath = string() and AllowedModule = atom(). erl_script_alias marks all URLs matching url-path as erl scheme scripts. A matching URL is mapped into a specific module and function. For example: @@ -531,140 +617,151 @@ bytes would refer to httpd_example:yahoo/3 or, if that did not exist, httpd_example:yahoo/2 and http://your.server.org/cgi-bin/example/other:yahoo would - not be allowed to execute. + not be allowed to execute.

+ {erl_script_nocache, boolean()} - - If erl_script_nocache is set to true the server will add +

If erl_script_nocache is set to true the server will add http header fields that prevents proxies from caching the page. This is generally a good idea for dynamic content, since - the content often vary between each request. Defaults to false. + the content often vary between each request. + Defaults to false.

+ {erl_script_timeout, integer()} - - If erl_script_timeout sets the time in seconds the server will +

If erl_script_timeout sets the time in seconds the server will wait between each chunk of data to be delivered through mod_esi:deliver/2. Defaults to 15. This is only relevant - for scripts that uses the erl scheme. + for scripts that uses the erl scheme.

+ {eval_script_alias, {URLPath, [AllowedModule]}} - - Where URLPath = string() and AllowedModule = atom(). + +

Where URLPath = string() and AllowedModule = atom(). Same as erl_script_alias but for scripts - using the eval scheme. Note that this is only supported - for backwards compatibility. The eval scheme is deprecated. + using the eval scheme. Note that this is only supported + for backwards compatibility. The eval scheme is deprecated.

+
- +

Log properties - requires mod_log

+ {error_log, path()} - - Defines the filename of the error log file to be used to log +

Defines the filename of the error log file to be used to log server errors. If the filename does not begin with a slash (/) - it is assumed to be relative to the server_root + it is assumed to be relative to the server_root.

+
+ {security_log, path()} - - Defines the filename of the access log file to be used to - log security events. If the filename does not begin with a slash - (/) it is assumed to be relative to the server_root. +

Defines the filename of the access log file to be used to + log security events. If the filename does not begin with a slash + (/) it is assumed to be relative to the server_root.

+ {transfer_log, path()} - - Defines the filename of the access log file to be used to +

Defines the filename of the access log file to be used to log incoming requests. If the filename does not begin with a - slash (/) it is assumed to be relative to the server_root. + slash (/) it is assumed to be relative to the server_root.

- +

Disk Log properties - requires mod_disk_log

+ {disk_log_format, internal | external} - - Defines the file-format of the log files see disk_log for +

Defines the file-format of the log files see disk_log for more information. If the internal file-format is used, the logfile will be repaired after a crash. When a log file is repaired data might get lost. When the external file-format is used httpd will not start if the log file is broken. Defaults to - external. + external.

+ {error_disk_log, internal | external} - - Defines the filename of the (disk_log(3)) error log file +

Defines the filename of the (disk_log(3)) error log file to be used to log server errors. If the filename does not begin - with a slash (/) it is assumed to be relative to the server_root. + with a slash (/) it is assumed to be relative to the server_root.

+ {error_disk_log_size, {MaxBytes, MaxFiles}} - - Where MaxBytes = integer() and MaxFiles = integer(). + +

Where MaxBytes = integer() and MaxFiles = integer(). Defines the properties of the (disk_log(3)) error log file. The disk_log(3) error log file is of type wrap log and max-bytes will be written to each file and max-files will be - used before the first file is truncated and reused. + used before the first file is truncated and reused.

+
+ {security_disk_log, path()} - - Defines the filename of the (disk_log(3)) access log file +

Defines the filename of the (disk_log(3)) access log file which logs incoming security events i.e authenticated requests. If the filename does not begin with a slash (/) it - is assumed to be relative to the server_root. + is assumed to be relative to the server_root.

+ {security_disk_log_size, {MaxBytes, MaxFiles}} - - Where MaxBytes = integer() and MaxFiles = integer(). + +

Where MaxBytes = integer() and MaxFiles = integer(). Defines the properties of the disk_log(3) access log file. The disk_log(3) access log file is of type wrap log and max-bytes will be written to each file and max-files will be - used before the first file is truncated and reused. + used before the first file is truncated and reused.

+
- {transfer_disk_log, path()} - + + {transfer_disk_log, path()} - Defines the filename of the (disk_log(3)) access log file +

Defines the filename of the (disk_log(3)) access log file which logs incoming requests. If the filename does not begin with a slash (/) it is assumed to be relative to the - server_root. + server_root.

+ {transfer_disk_log_size, {MaxBytes, MaxFiles}} - - Where MaxBytes = integer() and MaxFiles = integer(). + +

Where MaxBytes = integer() and MaxFiles = integer(). Defines the properties of the disk_log(3) access log file. The disk_log(3) access log file is of type wrap log and max-bytes will be written to each file and max-files will be - used before the first file is truncated and reused. + used before the first file is truncated and reused.

+
- +

Authentication properties - requires mod_auth

+

{directory, {path(), [{property(), term()}]}}

- +

Here follows the valid properties for directories

+ {allow_from, all | [RegxpHostString]} - - Defines a set of hosts which should be granted access to a +

Defines a set of hosts which should be granted access to a given directory. For example: @@ -672,34 +769,36 @@ bytes {allow_from, ["123.34.56.11", "150.100.23"] The host 123.34.56.11 and all machines on the 150.100.23 - subnet are allowed access. + subnet are allowed access.

+
+ {deny_from, all | [RegxpHostString]} - - Defines a set of hosts +

Defines a set of hosts which should be denied access to a given directory. For example: {deny_from, ["123.34.56.11", "150.100.23"] The host 123.34.56.11 and all machines on the 150.100.23 - subnet are not allowed access. + subnet are not allowed access.

+
+ {auth_type, plain | dets | mnesia} - - Sets the type of authentication database that is used for the +

Sets the type of authentication database that is used for the directory.The key difference between the different methods is that dynamic data can be saved when Mnesia and Dets is used. This property is called AuthDbType in the Apache like - configuration files. + configuration files.

+ {auth_user_file, path()} - - Sets the name of a file which contains the list of users and +

Sets the name of a file which contains the list of users and passwords for user authentication. filename can be either absolute or relative to the server_root. If using the plain storage method, this file is a plain text file, where @@ -717,12 +816,13 @@ bytes storage method. For security reasons, make sure that the auth_user_file is stored outside the document tree of the Web server. If it is placed in the directory which it protects, - clients will be able to download it. + clients will be able to download it.

+ {auth_group_file, path()} - - Sets the name of a file which contains the list of user + +

Sets the name of a file which contains the list of user groups for user authentication. Filename can be either absolute or relative to the server_root. If you use the plain storage method, the group file is a plain text file, where @@ -738,93 +838,109 @@ bytes For security reasons, make sure that the auth_group_file is stored outside the document tree of the Web server. If it is placed in the directory which it protects, clients will be - able to download it. + able to download it.

+
+ {auth_name, string()} - - Sets the name of the authorization realm (auth-domain) for +

Sets the name of the authorization realm (auth-domain) for a directory. This string informs the client about which user - name and password to use. + name and password to use.

+
+ {auth_access_password, string()} - - If set to other than "NoPassword" the password is required + +

If set to other than "NoPassword" the password is required for all API calls. If the password is set to "DummyPassword" the password must be changed before any other API calls. To secure the authenticating data the password must be changed after the web server is started since it otherwise is written in clear - text in the configuration file. + text in the configuration file.

+
+ {require_user, [string()]} - Defines users which should be granted access to a given - directory using a secret password. +

Defines users which should be granted access to a given + directory using a secret password.

+ {require_group, [string()]} - Defines users which should be granted access to a given - directory using a secret password. +

Defines users which should be granted access to a given + directory using a secret password.

- +

Htaccess authentication properties - requires mod_htaccess

+ {access_files, [path()]} - - Specify which filenames that are used for + +

Specify which filenames that are used for access-files. When a request comes every directory in the path to the requested asset will be searched after files with the names specified by this parameter. If such a file is found the file will be parsed and the restrictions specified in it will - be applied to the request. + be applied to the request.

- +

Security properties - requires mod_security

+

{security_directory, {path(), [{property(), term()}]}

- -

Here follows the valid properties for security directories

+ +

Here follows the valid properties for security directories

- {data_file, path()} - + + {data_file, path()} - Name of the security data file. The filename can either +

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. - - {max_retries, integer()} + store persistent data for the mod_security module.

+
- Specifies the maximum number of tries to authenticate a + + {max_retries, integer()} + +

Specifies the maximum number of tries to authenticate a user has before the user is blocked out. If a user successfully authenticates when the user has been blocked, the user will receive a 403 (Forbidden) response from the server. If the user makes a failed attempt while blocked the server will return 401 (Unauthorized), for security - reasons. Defaults to 3 may also be set to infinity. + reasons. + Defaults to 3 may also be set to infinity.

+
+ {block_time, integer()} - - Specifies the number of minutes a user is blocked. After + +

Specifies the number of minutes a user is blocked. After this amount of time, he automatically regains access. - Defaults to 60 + Defaults to 60.

+
+ {fail_expire_time, integer()} - - Specifies the number of minutes a failed user authentication +

Specifies the number of minutes a failed user authentication is remembered. If a user authenticates after this amount of time, his previous failed authentications are - forgotten. Defaults to 30 + forgotten. + Defaults to 30.

+
+ {auth_timeout, integer()} - Specifies the number of seconds a successful user authentication is remembered. After this time has passed, the @@ -835,6 +951,7 @@ bytes + info(Pid) -> info(Pid, Properties) -> [{Option, Value}] Fetches information about the HTTP server @@ -858,6 +975,7 @@ bytes + info(Address, Port) -> info(Address, Port, Properties) -> [{Option, Value}] Fetches information about the HTTP server @@ -883,6 +1001,7 @@ bytes + reload_config(Config, Mode) -> ok | {error, Reason} Reloads the HTTP server configuration without restarting the server. @@ -1003,6 +1122,7 @@ bytes
+ Module:do(ModData)-> {proceed, OldData} | {proceed, NewData} | {break, NewData} | done Called for each request to the Web server. @@ -1046,7 +1166,9 @@ bytes closing the connection.

+ + Module:load(Line, AccIn)-> eof | ok | {ok, AccOut} | {ok, AccOut, {Option, Value}} | {ok, AccOut, [{Option, Value}]} | {error, Reason} Load is used to convert a line in a Apache like config file to a {Option, Value} tuple. @@ -1068,7 +1190,9 @@ bytes

+ + Module:store({Option, Value}, Config)-> {ok, {Option, NewValue}} | {error, Reason} @@ -1092,6 +1216,7 @@ bytes + Module:remove(ConfigDB) -> ok | {error, Reason} Callback function that is called when the Web server is closed. @@ -1112,6 +1237,7 @@ bytes + parse_query(QueryString) -> [{Key,Value}] Parse incoming data to erl and eval scripts. @@ -1120,7 +1246,6 @@ bytes Value = string() -

parse_query/1 parses incoming data to erl and eval scripts (See mod_esi(3)) as defined in the standard URL format, that is '+' becomes 'space' and decoding of diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index cfc58b8ddb..2c96c43efb 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -33,6 +33,67 @@ +

Inets 5.9 + +
Improvements and New Features + + + + +

[httpd] Make the server header configurable with new config + option + server_tokens. + The value of the server header, which was previously hard-coded + (at compile time), is now possible to manipulate through the means + of the + server_tokens + config option.

+

Own Id: OTP-9805

+
+ +
+ +
+ +
Fixed Bugs and Malfunctions +

-

+ + + +
+ +
+ Incompatibilities +

-

+ + + +
+ +
+ +
Inets 5.8.1
Improvements and New Features

-

@@ -417,7 +478,7 @@

ossl will work for as long as the ssl application supports it.

See the httpd - socket_type + socket_type communication property or the httpc request/4,5 function for more info.

@@ -436,7 +497,7 @@

[httpd] Wrong - security property + security property names used in documentation.

security_data_file used instead of data_file.

security_max_retries used instead of max_retries.

@@ -620,7 +681,7 @@ the essl tag instead.

See the http_option option in the request/4,5 or - the socket-type + the socket-type section of the Communication properties chapter for more info,

Own Id: OTP-7907

@@ -637,9 +698,9 @@

[httpd] - Improved mod_alias. Now able to do better URL rewrites.

See - URL aliasing properties + URL aliasing properties and the - CGI properties + CGI properties section(s) for more info,

Own Id: OTP-8573

@@ -1225,7 +1286,7 @@

Default is inet6fb4 which emulates the behaviour of the previous version.

See the - Communication properties + Communication properties section for more info.

Own Id: OTP-8069

Aux Id: seq11086

diff --git a/lib/inets/src/http_server/Makefile b/lib/inets/src/http_server/Makefile index 55cc68dede..c341a2cec7 100644 --- a/lib/inets/src/http_server/Makefile +++ b/lib/inets/src/http_server/Makefile @@ -88,6 +88,8 @@ ERL_FILES = $(MODULES:%=%.erl) TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) +INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' + # ---------------------------------------------------- # FLAGS diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl index 7646300409..2ffd134d3d 100644 --- a/lib/inets/src/http_server/httpd_conf.erl +++ b/lib/inets/src/http_server/httpd_conf.erl @@ -210,12 +210,32 @@ load("MaxBodySize " ++ MaxBodySize, []) -> {ok, Integer} -> {ok, [], {max_body_size,Integer}}; {error, _} -> - {error, ?NICE(clean(MaxBodySize)++ + {error, ?NICE(clean(MaxBodySize) ++ " is an invalid number of MaxBodySize")} end; load("ServerName " ++ ServerName, []) -> - {ok,[],{server_name,clean(ServerName)}}; + {ok,[], {server_name, clean(ServerName)}}; + +load("ServerTokens " ++ ServerTokens, []) -> + %% These are the valid *plain* server tokens: + %% sprod, major, minor, minimum, os, full + %% It can also be a "private" server token: private: + case string:tokens(ServerTokens, [$:]) of + ["private", Private] -> + {ok,[], {server_tokens, clean(Private)}}; + [TokStr] -> + Tok = list_to_atom(clean(TokStr)), + case lists:member(Tok, [prod, major, minor, minimum, os, full]) of + true -> + {ok,[], {server_tokens, Tok}}; + false -> + {error, ?NICE(clean(ServerTokens) ++ + " is an invalid ServerTokens")} + end; + _ -> + {error, ?NICE(clean(ServerTokens) ++ " is an invalid ServerTokens")} + end; load("SocketType " ++ SocketType, []) -> %% ssl is the same as HTTP_DEFAULT_SSL_KIND @@ -537,6 +557,20 @@ validate_config_params([{server_name, Value} | Rest]) validate_config_params([{server_name, Value} | _]) -> throw({server_name, Value}); +validate_config_params([{server_tokens, Value} | Rest]) + when is_atom(Value) -> + case lists:member(Value, plain_server_tokens()) of + true -> + validate_config_params(Rest); + false -> + throw({server_tokens, Value}) + end; +validate_config_params([{server_tokens, {private, Value}} | Rest]) + when is_list(Value) -> + validate_config_params(Rest); +validate_config_params([{server_tokens, Value} | _]) -> + throw({server_tokens, Value}); + validate_config_params([{socket_type, Value} | Rest]) when (Value =:= ip_comm) orelse (Value =:= ssl) orelse @@ -737,9 +771,73 @@ store({log_format, LogFormat}, _ConfigList) store({log_format, LogFormat}, _ConfigList) when (LogFormat =:= compact) orelse (LogFormat =:= pretty) -> {ok, {log_format, LogFormat}}; +store({server_tokens, ServerTokens} = Entry, _ConfigList) -> + Server = server(ServerTokens), + {ok, [Entry, {server, Server}]}; store(ConfigListEntry, _ConfigList) -> {ok, ConfigListEntry}. + +%% The SERVER_SOFTWARE macro has the following structure: +%% / +%% Example: "inets/1.2.3" +%% So, with this example (on a linux machine, with OTP R15B), +%% this will result in: +%% prod: "inets" +%% major: "inets/1" +%% minor: "inets/1.2" +%% minimal: "inets/1.2.3" +%% os: "inets/1.2.3 (unix) +%% full: "inets/1.2.3 (unix/linux) OTP/R15B" +%% Note that the format of SERVER_SOFTWARE is that of 'minimal'. +%% Also, there will always be atleast two digits in a version: +%% Not just 1 but 1.0 +%% +%% We have already checked that the value is valid, +%% so there is no need to check enything here. +%% +server(prod = _ServerTokens) -> + [Prod|_Version] = string:tokens(?SERVER_SOFTWARE, [$/]), + Prod; +server(major = _ServerTokens) -> + [Prod|Version] = string:tokens(?SERVER_SOFTWARE, [$/]), + [Major|_] = string:tokens(Version, [$.]), + Prod ++ "/" ++ Major; +server(minor = _ServerTokens) -> + [Prod|Version] = string:tokens(?SERVER_SOFTWARE, [$/]), + [Major,Minor|_] = string:tokens(Version, [$.]), + Prod ++ "/" ++ Major ++ "." ++ Minor; +server(minimal = _ServerTokens) -> + %% This is the default + ?SERVER_SOFTWARE; +server(os = _ServerTokens) -> + OS = os_info(partial), + lists:flatten(io_lib:format("~s ~s", [?SERVER_SOFTWARE, OS])); +server(full = _ServerTokens) -> + OTPRelease = otp_release(), + OS = os_info(full), + lists:flatten( + io_lib:format("~s ~s OTP/~s", [?SERVER_SOFTWARE, OS, OTPRelease])); +server({private, Server} = _ServerTokens) when is_list(Server) -> + %% The user provide its own + Server; +server(_) -> + ?SERVER_SOFTWARE. + +os_info(Info) -> + case os:type() of + {OsFamily, _OsName} when Info =:= partial -> + lists:flatten(io_lib:format("(~w)", [OsFamily])); + {OsFamily, OsName} -> + lists:flatten(io_lib:format("(~w/~w)", [OsFamily, OsName])); + OsFamily -> + lists:flatten(io_lib:format("(~w)", [OsFamily])) + end. + +otp_release() -> + erlang:system_info(otp_release). + + %% Phase 3: Remove remove_all(ConfigDB) -> Modules = httpd_util:lookup(ConfigDB,modules,[]), @@ -1159,6 +1257,10 @@ ssl_ca_certificate_file(ConfigDB) -> [{cacertfile, File}] end. +plain_server_tokens() -> + [prod, major, minor, minimum, os, full]. + error_report(Where,M,F,Error) -> error_logger:error_report([{?MODULE, Where}, {apply, {M, F, []}}, Error]). + diff --git a/lib/inets/src/http_server/httpd_response.erl b/lib/inets/src/http_server/httpd_response.erl index dd7223876e..2dedb088e4 100644 --- a/lib/inets/src/http_server/httpd_response.erl +++ b/lib/inets/src/http_server/httpd_response.erl @@ -144,10 +144,14 @@ send_response(ModData, Header, Body) -> end end. -send_header(#mod{socket_type = Type, socket = Sock, - http_version = Ver, connection = Conn} = _ModData, +send_header(#mod{socket_type = Type, + socket = Sock, + http_version = Ver, + connection = Conn, + config_db = ConfigDb} = _ModData, StatusCode, KeyValueTupleHeaders) -> - Headers = create_header(lists:map(fun transform/1, KeyValueTupleHeaders)), + Headers = create_header(ConfigDb, + lists:map(fun transform/1, KeyValueTupleHeaders)), NewVer = case {Ver, StatusCode} of {[], _} -> %% May be implicit! @@ -275,13 +279,20 @@ cache_headers(#mod{config_db = Db}) -> [] end. -create_header(KeyValueTupleHeaders) -> - NewHeaders = add_default_headers([{"date", httpd_util:rfc1123_date()}, - {"content-type", "text/html"}, - {"server", ?SERVER_SOFTWARE}], - KeyValueTupleHeaders), +create_header(ConfigDb, KeyValueTupleHeaders) -> + Date = httpd_util:rfc1123_date(), + ContentType = "text/html", + Server = server(ConfigDb), + NewHeaders = add_default_headers([{"date", Date}, + {"content-type", ContentType}, + {"server", Server}], + KeyValueTupleHeaders), lists:map(fun fix_header/1, NewHeaders). + +server(ConfigDb) -> + httpd_util:lookup(ConfigDb, server, ?SERVER_SOFTWARE). + fix_header({Key0, Value}) -> %% make sure first letter is capital Words1 = string:tokens(Key0, "-"), diff --git a/lib/inets/src/http_server/httpd_script_env.erl b/lib/inets/src/http_server/httpd_script_env.erl index d3115150b0..a5613ba4a4 100644 --- a/lib/inets/src/http_server/httpd_script_env.erl +++ b/lib/inets/src/http_server/httpd_script_env.erl @@ -50,29 +50,44 @@ create_env(ScriptType, ModData, ScriptElements) -> %%%======================================================================== %%% Internal functions %%%======================================================================== + +which_server(#mod{config_db = ConfigDb}) -> + httpd_util:lookup(ConfigDb, server, ?SERVER_SOFTWARE). + +which_port(#mod{config_db = ConfigDb}) -> + httpd_util:lookup(ConfigDb, port, 80). + +which_peername(#mod{init_data = #init_data{peername = {_, RemoteAddr}}}) -> + RemoteAddr. + +which_resolve(#mod{init_data = #init_data{resolve = Resolve}}) -> + Resolve. + +which_method(#mod{method = Method}) -> + Method. + +which_request_uri(#mod{request_uri = RUri}) -> + RUri. + create_basic_elements(esi, ModData) -> - {_, RemoteAddr} = (ModData#mod.init_data)#init_data.peername, - [{server_software, ?SERVER_SOFTWARE}, - {server_name, (ModData#mod.init_data)#init_data.resolve}, - {gateway_interface,?GATEWAY_INTERFACE}, - {server_protocol, ?SERVER_PROTOCOL}, - {server_port, httpd_util:lookup(ModData#mod.config_db,port,80)}, - {request_method, ModData#mod.method}, - {remote_addr, RemoteAddr}, - {script_name, ModData#mod.request_uri}]; + [{server_software, which_server(ModData)}, + {server_name, which_resolve(ModData)}, + {gateway_interface, ?GATEWAY_INTERFACE}, + {server_protocol, ?SERVER_PROTOCOL}, + {server_port, which_port(ModData)}, + {request_method, which_method(ModData)}, + {remote_addr, which_peername(ModData)}, + {script_name, which_request_uri(ModData)}]; create_basic_elements(cgi, ModData) -> - {_, RemoteAddr} = (ModData#mod.init_data)#init_data.peername, - [{"SERVER_SOFTWARE",?SERVER_SOFTWARE}, - {"SERVER_NAME", (ModData#mod.init_data)#init_data.resolve}, - {"GATEWAY_INTERFACE",?GATEWAY_INTERFACE}, - {"SERVER_PROTOCOL",?SERVER_PROTOCOL}, - {"SERVER_PORT", - integer_to_list(httpd_util:lookup( - ModData#mod.config_db, port, 80))}, - {"REQUEST_METHOD", ModData#mod.method}, - {"REMOTE_ADDR", RemoteAddr}, - {"SCRIPT_NAME", ModData#mod.request_uri}]. + [{"SERVER_SOFTWARE", which_server(ModData)}, + {"SERVER_NAME", which_resolve(ModData)}, + {"GATEWAY_INTERFACE", ?GATEWAY_INTERFACE}, + {"SERVER_PROTOCOL", ?SERVER_PROTOCOL}, + {"SERVER_PORT", integer_to_list(which_port(ModData))}, + {"REQUEST_METHOD", which_method(ModData)}, + {"REMOTE_ADDR", which_peername(ModData)}, + {"SCRIPT_NAME", which_request_uri(ModData)}]. create_http_header_elements(ScriptType, Headers) -> create_http_header_elements(ScriptType, Headers, []). @@ -80,7 +95,7 @@ create_http_header_elements(ScriptType, Headers) -> create_http_header_elements(_, [], Acc) -> Acc; create_http_header_elements(ScriptType, [{Name, [Value | _] = Values } | - Headers], Acc) + Headers], Acc) when is_list(Value) -> NewName = lists:map(fun(X) -> if X == $- -> $_; true -> X end end, Name), Element = http_env_element(ScriptType, NewName, multi_value(Values)), diff --git a/lib/inets/src/inets_app/inets.mk b/lib/inets/src/inets_app/inets.mk index 194b4ca2b1..d24cc0aea3 100644 --- a/lib/inets/src/inets_app/inets.mk +++ b/lib/inets/src/inets_app/inets.mk @@ -41,8 +41,6 @@ INETS_APP_VSN_COMPILE_FLAGS = \ +'{parse_transform,sys_pre_attributes}' \ +'{attribute,insert,app_vsn,$(APP_VSN)}' -INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' - INETS_ERL_COMPILE_FLAGS += \ -pa $(ERL_TOP)/lib/inets/ebin \ $(INETS_APP_VSN_COMPILE_FLAGS) diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk index 77eb43a7ed..488947c3a1 100644 --- a/lib/inets/vsn.mk +++ b/lib/inets/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% APPLICATION = inets -INETS_VSN = 5.8.1 +INETS_VSN = 5.9 PRE_VSN = APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)" -- cgit v1.2.3 From 2919a7505963054e442cf2e8fc9ff46739a0d0d9 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 8 Dec 2011 14:46:18 +0100 Subject: [inets] Added more error info when connect fails --- lib/inets/src/http_client/httpc_handler.erl | 16 +++++--- lib/inets/src/inets_app/inets.appup.src | 64 ++++++++++------------------- 2 files changed, 32 insertions(+), 48 deletions(-) diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl index bfe9b14ef6..714fd6f16d 100644 --- a/lib/inets/src/http_client/httpc_handler.erl +++ b/lib/inets/src/http_client/httpc_handler.erl @@ -852,13 +852,14 @@ connect(SocketType, ToAddress, inet6fb4 -> Opts3 = [inet6 | Opts2], case http_transport:connect(SocketType, ToAddress, Opts3, Timeout) of - {error, _Reason} = Error -> + {error, Reason6} -> Opts4 = [inet | Opts2], case http_transport:connect(SocketType, ToAddress, Opts4, Timeout) of - {error, _} -> - %% Reply with the "original" error - Error; + {error, Reason4} -> + {error, {failed_connect, + [{inet6, Opts3, Reason6}, + {inet, Opts4, Reason4}]}}; OK -> OK end; @@ -867,7 +868,12 @@ connect(SocketType, ToAddress, end; _ -> Opts3 = [IpFamily | Opts2], - http_transport:connect(SocketType, ToAddress, Opts3, Timeout) + case http_transport:connect(SocketType, ToAddress, Opts3, Timeout) of + {error, Reason} -> + {error, {failed_connect, [{IpFamily, Opts3, Reason}]}}; + Else -> + Else + end end. connect_and_send_first_request(Address, Request, #state{options = Options} = State) -> diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index e80cb2a23b..f47ca98d1a 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -18,65 +18,43 @@ {"%VSN%", [ + {"5.8.1", + [ + {load_module, inets, soft_purge, soft_purge, [inets_trace]}, + {update, httpc_handler, soft, soft_purge, soft_purge, []}, + {add_module, inets_trace} + ] + }, {"5.8", [ + {load_module, inets, soft_purge, soft_purge, [inets_trace]}, {load_module, ftp, soft_purge, soft_purge, []}, {update, httpc_handler, {advanced, upgrade_from_pre_5_8_1}, soft_purge, soft_purge, []}, {update, httpc_manager, {advanced, upgrade_from_pre_5_8_1}, - soft_purge, soft_purge, [httpc_handler]} - ] - }, - {"5.7.2", - [ - {restart_application, inets} - ] - }, - {"5.7.1", - [ - {restart_application, inets} + soft_purge, soft_purge, [httpc_handler]}, + {add_module, inets_trace} ] - }, - {"5.7", + } + ], + [ + {"5.8.1", [ - {restart_application, inets} + {load_module, inets, soft_purge, soft_purge, []}, + {update, httpc_handler, soft, soft_purge, soft_purge, []}, + {remove, {inets_trace, soft_purge, brutal_purge}} ] }, - {"5.6", - [ - {restart_application, inets} - ] - } - ], - [ {"5.8", [ + {load_module, inets, soft_purge, soft_purge, [inets_trace]}, {load_module, ftp, soft_purge, soft_purge, []}, {update, httpc_handler, {advanced, upgrade_from_pre_5_8_1}, soft_purge, soft_purge, []}, {update, httpc_manager, {advanced, upgrade_from_pre_5_8_1}, - soft_purge, soft_purge, [httpc_handler]} - ] - }, - {"5.7.2", - [ - {restart_application, inets} - ] - }, - {"5.7.1", - [ - {restart_application, inets} - ] - }, - {"5.7", - [ - {restart_application, inets} - ] - }, - {"5.6", - [ - {restart_application, inets} + soft_purge, soft_purge, [httpc_handler]}, + {remove, {inets_trace, soft_purge, brutal_purge}} ] - } + } ] }. -- cgit v1.2.3 From c09e8f7c1b7f77ba083d71b13dc02f599a1c1481 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 15 Dec 2011 09:19:57 +0100 Subject: [inets] Added more (printed) system info during test case init Print some host info (os, os-type and sys arch and so on) during test case init. --- lib/inets/test/httpc_SUITE.erl | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 881266b70a..3276481fed 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -244,6 +244,32 @@ init_per_testcase(Case, Timeout, Config) -> io:format(user, "~n~n*** INIT ~w:~w[~w] ***" "~n~n", [?MODULE, Case, Timeout]), + + io:format("init_per_testcase(~w) -> entry with" + "~n Timeout: ~p" + "~n Config: ~p" + "~n" + "~nwhen" + "~n" + "~n OS Type: ~p" + "~n OS version: ~p" + "~n Sys Arch: ~p" + "~n CPU Topology: ~p" + "~n Num logical procs: ~p" + "~n SMP support: ~p" + "~n Num schedulers: ~p" + "~n Scheduler bindings: ~p" + "~n Wordsize: ~p" + "~n~n", [Case, Timeout, Config, + os:type(), os:version(), + erlang:system_info(system_architecture), + erlang:system_info(cpu_topology), + erlang:system_info(logical_processors), + erlang:system_info(smp_support), + erlang:system_info(schedulers), + erlang:system_info(scheduler_bindings), + erlang:system_info(wordsize)]), + PrivDir = ?config(priv_dir, Config), application:stop(inets), Dog = test_server:timetrap(inets_test_lib:minutes(Timeout)), @@ -355,6 +381,10 @@ init_per_testcase(Case, Timeout, Config) -> end; _ -> + %% Try inet6fb4 on windows... + %% ...but since I dont know exactly how to test this... + %% ...this should also effect the server... + TmpConfig2 = lists:keydelete(local_server, 1, TmpConfig), %% Will start inets Server = start_http_server(PrivDir, IpConfFile), @@ -367,6 +397,9 @@ init_per_testcase(Case, Timeout, Config) -> inets:enable_trace(max, io, httpc), %% inets:enable_trace(max, io, all), %% snmp:set_trace([gen_tcp]), + io:format("init_per_testcase(~w) -> done when" + "~n NewConfig: ~p" + "~n~n", [Case, NewConfig]), NewConfig. -- cgit v1.2.3 From 411da4a989320ba7f7b775e696b94df4c6b13c59 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 15 Dec 2011 11:54:58 +0100 Subject: [inets] Moved (dbg) trace utility functions to own module (inets_trace) --- lib/inets/src/inets_app/Makefile | 3 +- lib/inets/src/inets_app/inets.app.src | 5 +- lib/inets/src/inets_app/inets.erl | 267 +-------------------- lib/inets/src/inets_app/inets_internal.hrl | 6 +- lib/inets/src/inets_app/inets_trace.erl | 357 +++++++++++++++++++++++++++++ 5 files changed, 372 insertions(+), 266 deletions(-) create mode 100644 lib/inets/src/inets_app/inets_trace.erl diff --git a/lib/inets/src/inets_app/Makefile b/lib/inets/src/inets_app/Makefile index d99e33b4ea..6da6a1d79f 100644 --- a/lib/inets/src/inets_app/Makefile +++ b/lib/inets/src/inets_app/Makefile @@ -46,7 +46,8 @@ MODULES = \ inets_service \ inets_app \ inets_sup \ - inets_regexp + inets_regexp \ + inets_trace INTERNAL_HRL_FILES = inets_internal.hrl EXTERNAL_HRL_FILES = ../../include/httpd.hrl \ diff --git a/lib/inets/src/inets_app/inets.app.src b/lib/inets/src/inets_app/inets.app.src index 1db7ed2c30..4aea2ef3d7 100644 --- a/lib/inets/src/inets_app/inets.app.src +++ b/lib/inets/src/inets_app/inets.app.src @@ -18,14 +18,15 @@ %% {application,inets, - [{description,"INETS CXC 138 49"}, - {vsn,"%VSN%"}, + [{description, "INETS CXC 138 49"}, + {vsn, "%VSN%"}, {modules,[ inets, inets_sup, inets_app, inets_service, inets_regexp, + inets_trace, %% FTP ftp, diff --git a/lib/inets/src/inets_app/inets.erl b/lib/inets/src/inets_app/inets.erl index 054468e445..8e79f8d456 100644 --- a/lib/inets/src/inets_app/inets.erl +++ b/lib/inets/src/inets_app/inets.erl @@ -28,7 +28,7 @@ stop/0, stop/2, services/0, services_info/0, service_names/0]). --export([enable_trace/2, enable_trace/3, disable_trace/0, set_trace/1, +-export([enable_trace/2, enable_trace/3, disable_trace/0, set_trace/1, report_event/4]). -export([versions/0, print_version_info/0, print_version_info/1]). @@ -409,47 +409,8 @@ service_names() -> %% Severity withing Limit) will be written to stdout using io:format. %% %%----------------------------------------------------------------- -enable_trace(Level, Dest) -> - enable_trace(Level, Dest, all). - -enable_trace(Level, Dest, Service) -> - case valid_trace_service(Service) of - true -> - enable_trace2(Level, Dest, Service); - false -> - {error, {invalid_service, Service}} - end. - -enable_trace2(Level, File, Service) - when is_list(File) -> - case file:open(File, [write]) of - {ok, Fd} -> - HandleSpec = {fun handle_trace/2, {Service, Fd}}, - do_enable_trace(Level, process, HandleSpec); - Err -> - Err - end; -enable_trace2(Level, Port, _) when is_integer(Port) -> - do_enable_trace(Level, port, dbg:trace_port(ip, Port)); -enable_trace2(Level, io, Service) -> - HandleSpec = {fun handle_trace/2, {Service, standard_io}}, - do_enable_trace(Level, process, HandleSpec); -enable_trace2(Level, {Fun, _Data} = HandleSpec, _) when is_function(Fun) -> - do_enable_trace(Level, process, HandleSpec). - -do_enable_trace(Level, Type, HandleSpec) -> - case dbg:tracer(Type, HandleSpec) of - {ok, _} -> - set_trace(Level), - ok; - Error -> - Error - end. - -valid_trace_service(all) -> - true; -valid_trace_service(Service) -> - lists:member(Service, [httpc, httpd, ftpc, tftp]). +enable_trace(Level, Dest) -> inets_trace:enable(Level, Dest). +enable_trace(Level, Dest, Service) -> inets_trace:enable(Level, Dest, Service). %%----------------------------------------------------------------- @@ -458,12 +419,7 @@ valid_trace_service(Service) -> %% Description: %% This function is used to stop tracing. %%----------------------------------------------------------------- -disable_trace() -> - %% This is to make handle_trace/2 close the output file (if the - %% event gets there before dbg closes) - inets:report_event(100, "stop trace", stop_trace, [stop_trace]), - dbg:stop(). - +disable_trace() -> inets_trace:disable(). %%----------------------------------------------------------------- @@ -476,60 +432,7 @@ disable_trace() -> %% This function is used to change the trace level when tracing has %% already been started. %%----------------------------------------------------------------- -set_trace(Level) -> - set_trace(Level, all). - -set_trace(Level, Service) -> - Pat = make_pattern(?MODULE, Service, Level), - change_pattern(Pat). - -make_pattern(Mod, Service, Level) - when is_atom(Mod) andalso is_atom(Service) -> - case Level of - min -> - {Mod, Service, []}; - max -> - Head = ['$1', '_', '_', '_'], - Body = [], - Cond = [], - {Mod, Service, [{Head, Cond, Body}]}; - DetailLevel when is_integer(DetailLevel) -> - Head = ['$1', '_', '_', '_'], - Body = [], - Cond = [{ '=<', '$1', DetailLevel}], - {Mod, Service, [{Head, Cond, Body}]}; - _ -> - exit({bad_level, Level}) - end. - -change_pattern({Mod, Service, Pattern}) - when is_atom(Mod) andalso is_atom(Service) -> - MFA = {Mod, report_event, 4}, - case Pattern of - [] -> - try - error_to_exit(ctp, dbg:ctp(MFA)), - error_to_exit(p, dbg:p(all, clear)) - catch - exit:{Where, Reason} -> - {error, {Where, Reason}} - end; - List when is_list(List) -> - try - error_to_exit(ctp, dbg:ctp(MFA)), - error_to_exit(tp, dbg:tp(MFA, Pattern)), - error_to_exit(p, dbg:p(all, [call, timestamp])) - catch - exit:{Where, Reason} -> - {error, {Where, Reason}} - end - end, - ok. - -error_to_exit(_Where, {ok, _} = OK) -> - OK; -error_to_exit(Where, {error, Reason}) -> - exit({Where, Reason}). +set_trace(Level) -> inets_trace:set_level(Level). %%----------------------------------------------------------------- @@ -546,164 +449,8 @@ error_to_exit(Where, {error, Reason}) -> %% put trace on this function. %%----------------------------------------------------------------- -report_event(Severity, Label, Service, Content) - when (is_integer(Severity) andalso - (Severity >= 0) andalso (100 >= Severity)) andalso - is_list(Label) andalso - is_atom(Service) andalso - is_list(Content) -> - hopefully_traced. - - -%% ---------------------------------------------------------------------- -%% handle_trace(Event, Fd) -> Verbosity -%% -%% Parameters: -%% Event -> The trace event (only megaco 'trace_ts' events are printed) -%% Fd -> standard_io | file_descriptor() | trace_port() -%% -%% Description: -%% This function is used to "receive" and print the trace events. -%% Events are printed if: -%% - Verbosity is max -%% - Severity is =< Verbosity (e.g. Severity = 30, and Verbosity = 40) -%% Events are not printed if: -%% - Verbosity is min -%% - Severity is > Verbosity -%%----------------------------------------------------------------- - -handle_trace(_, closed_file = Fd) -> - Fd; -handle_trace({trace_ts, _Who, call, - {?MODULE, report_event, - [_Sev, "stop trace", stop_trace, [stop_trace]]}, - Timestamp}, - {_, standard_io} = Fd) -> - (catch io:format(standard_io, "stop trace at ~s~n", [format_timestamp(Timestamp)])), - Fd; -handle_trace({trace_ts, _Who, call, - {?MODULE, report_event, - [_Sev, "stop trace", stop_trace, [stop_trace]]}, - Timestamp}, - standard_io = Fd) -> - (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), - Fd; -handle_trace({trace_ts, _Who, call, - {?MODULE, report_event, - [_Sev, "stop trace", stop_trace, [stop_trace]]}, - Timestamp}, - {_Service, Fd}) -> - (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), - (catch file:close(Fd)), - closed_file; -handle_trace({trace_ts, _Who, call, - {?MODULE, report_event, - [_Sev, "stop trace", stop_trace, [stop_trace]]}, - Timestamp}, - Fd) -> - (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), - (catch file:close(Fd)), - closed_file; -handle_trace({trace_ts, Who, call, - {?MODULE, report_event, - [Sev, Label, Service, Content]}, Timestamp}, - Fd) -> - (catch print_inets_trace(Fd, Sev, Timestamp, Who, - Label, Service, Content)), - Fd; -handle_trace(Event, Fd) -> - (catch print_trace(Fd, Event)), - Fd. - - -print_inets_trace({Service, Fd}, - Sev, Timestamp, Who, Label, Service, Content) -> - do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content); -print_inets_trace({ServiceA, Fd}, - Sev, Timestamp, Who, Label, ServiceB, Content) - when (ServiceA =:= all) -> - do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, ServiceB, Content); -print_inets_trace({ServiceA, _Fd}, - _Sev, _Timestamp, _Who, _Label, ServiceB, _Content) - when ServiceA =/= ServiceB -> - ok; -print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) -> - do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content). - -do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) -> - Ts = format_timestamp(Timestamp), - io:format(Fd, "[inets ~w trace ~w ~w ~s] ~s " - "~n Content: ~p" - "~n", - [Service, Sev, Who, Ts, Label, Content]). - -print_trace({_, Fd}, Event) -> - do_print_trace(Fd, Event); -print_trace(Fd, Event) -> - do_print_trace(Fd, Event). - -do_print_trace(Fd, {trace, Who, What, Where}) -> - io:format(Fd, "[trace]" - "~n Who: ~p" - "~n What: ~p" - "~n Where: ~p" - "~n", [Who, What, Where]); - -do_print_trace(Fd, {trace, Who, What, Where, Extra}) -> - io:format(Fd, "[trace]" - "~n Who: ~p" - "~n What: ~p" - "~n Where: ~p" - "~n Extra: ~p" - "~n", [Who, What, Where, Extra]); - -do_print_trace(Fd, {trace_ts, Who, What, Where, When}) -> - Ts = format_timestamp(When), - io:format(Fd, "[trace ~s]" - "~n Who: ~p" - "~n What: ~p" - "~n Where: ~p" - "~n", [Ts, Who, What, Where]); - -do_print_trace(Fd, {trace_ts, Who, What, Where, Extra, When}) -> - Ts = format_timestamp(When), - io:format(Fd, "[trace ~s]" - "~n Who: ~p" - "~n What: ~p" - "~n Where: ~p" - "~n Extra: ~p" - "~n", [Ts, Who, What, Where, Extra]); - -do_print_trace(Fd, {seq_trace, What, Where}) -> - io:format(Fd, "[seq trace]" - "~n What: ~p" - "~n Where: ~p" - "~n", [What, Where]); - -do_print_trace(Fd, {seq_trace, What, Where, When}) -> - Ts = format_timestamp(When), - io:format(Fd, "[seq trace ~s]" - "~n What: ~p" - "~n Where: ~p" - "~n", [Ts, What, Where]); - -do_print_trace(Fd, {drop, Num}) -> - io:format(Fd, "[drop trace] ~p~n", [Num]); - -do_print_trace(Fd, Trace) -> - io:format(Fd, "[trace] " - "~n ~p" - "~n", [Trace]). - - -format_timestamp({_N1, _N2, N3} = Now) -> - {Date, Time} = calendar:now_to_datetime(Now), - {YYYY,MM,DD} = Date, - {Hour,Min,Sec} = Time, - FormatDate = - io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w", - [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]), - lists:flatten(FormatDate). +report_event(Severity, Label, Service, Content) -> + inets_trace:report_event(Severity, Label, Service, Content). %%-------------------------------------------------------------------- diff --git a/lib/inets/src/inets_app/inets_internal.hrl b/lib/inets/src/inets_app/inets_internal.hrl index 55c3669e4a..e56af3b59d 100644 --- a/lib/inets/src/inets_app/inets_internal.hrl +++ b/lib/inets/src/inets_app/inets_internal.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% Copyright Ericsson AB 2005-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -24,8 +24,8 @@ %% Various trace macros -define(report(Severity, Label, Service, Content), - inets:report_event(Severity, Label, Service, - [{module, ?MODULE}, {line, ?LINE} | Content])). + inets_trace:report_event(Severity, Label, Service, + [{module, ?MODULE}, {line, ?LINE} | Content])). -define(report_important(Label, Service, Content), ?report(20, Label, Service, Content)). -define(report_verbose(Label, Service, Content), diff --git a/lib/inets/src/inets_app/inets_trace.erl b/lib/inets/src/inets_app/inets_trace.erl new file mode 100644 index 0000000000..9369293d28 --- /dev/null +++ b/lib/inets/src/inets_app/inets_trace.erl @@ -0,0 +1,357 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 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 +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% Purpose: The main interface module of the inets application +%%---------------------------------------------------------------------- + +-module(inets_trace). + +%% API +-export([enable/2, enable/3, + disable/0, + set_level/1, set_level/2, + report_event/4]). + + +%%==================================================================== +%% API +%%==================================================================== + +%%----------------------------------------------------------------- +%% enable(Level, Destination) -> void() +%% enable(Level, Destination, Service) -> void() +%% +%% Parameters: +%% Level -> max | min | integer() +%% Destination -> File | Port | io | HandlerSpec +%% Service -> httpc | httpd | ftpc | tftp | all +%% File -> string() +%% Port -> integer() +%% Verbosity -> true | false +%% HandlerSpec = {function(), Data} +%% Data = term() +%% +%% Description: +%% This function is used to start tracing at level Level and send +%% the result either to the file File, the port Port or to a +%% trace handler. +%% Note that it starts a tracer server. +%% When Destination is the atom io (or the tuple {io, Verbosity}), +%% all (printable) inets trace events (trace_ts events which has +%% Severity withing Limit) will be written to stdout using io:format. +%% +%%----------------------------------------------------------------- +enable(Level, Dest) -> + enable(Level, Dest, all). + +enable(Level, Dest, Service) -> + case valid_trace_service(Service) of + true -> + enable2(Level, Dest, Service); + false -> + {error, {invalid_service, Service}} + end. + +enable2(Level, File, Service) + when is_list(File) -> + case file:open(File, [write]) of + {ok, Fd} -> + HandleSpec = {fun handle_trace/2, {Service, Fd}}, + do_enable(Level, process, HandleSpec); + Err -> + Err + end; +enable2(Level, Port, _) when is_integer(Port) -> + do_enable(Level, port, dbg:trace_port(ip, Port)); +enable2(Level, io, Service) -> + HandleSpec = {fun handle_trace/2, {Service, standard_io}}, + do_enable(Level, process, HandleSpec); +enable2(Level, {Fun, _Data} = HandleSpec, _) when is_function(Fun) -> + do_enable(Level, process, HandleSpec). + +do_enable(Level, Type, HandleSpec) -> + case dbg:tracer(Type, HandleSpec) of + {ok, _} -> + set_level(Level), + ok; + Error -> + Error + end. + +valid_trace_service(all) -> + true; +valid_trace_service(Service) -> + lists:member(Service, [httpc, httpd, ftpc, tftp]). + + +%%----------------------------------------------------------------- +%% disable() -> void() +%% +%% Description: +%% This function is used to stop tracing. +%%----------------------------------------------------------------- + +disable() -> + %% This is to make handle_trace/2 close the output file (if the + %% event gets there before dbg closes) + inets_trace:report_event(100, "stop trace", stop_trace, [stop_trace]), + dbg:stop(). + + + +%%----------------------------------------------------------------- +%% set_level(Level) -> void() +%% +%% Parameters: +%% Level -> max | min | integer() +%% +%% Description: +%% This function is used to change the trace level when tracing has +%% already been started. +%%----------------------------------------------------------------- +set_level(Level) -> + set_level(Level, all). + +set_level(Level, Service) -> + Pat = make_pattern(?MODULE, Service, Level), + change_pattern(Pat). + +make_pattern(Mod, Service, Level) + when is_atom(Mod) andalso is_atom(Service) -> + case Level of + min -> + {Mod, Service, []}; + max -> + Head = ['$1', '_', '_', '_'], + Body = [], + Cond = [], + {Mod, Service, [{Head, Cond, Body}]}; + DetailLevel when is_integer(DetailLevel) -> + Head = ['$1', '_', '_', '_'], + Body = [], + Cond = [{ '=<', '$1', DetailLevel}], + {Mod, Service, [{Head, Cond, Body}]}; + _ -> + exit({bad_level, Level}) + end. + +change_pattern({Mod, Service, Pattern}) + when is_atom(Mod) andalso is_atom(Service) -> + MFA = {Mod, report_event, 4}, + case Pattern of + [] -> + try + error_to_exit(ctp, dbg:ctp(MFA)), + error_to_exit(p, dbg:p(all, clear)) + catch + exit:{Where, Reason} -> + {error, {Where, Reason}} + end; + List when is_list(List) -> + try + error_to_exit(ctp, dbg:ctp(MFA)), + error_to_exit(tp, dbg:tp(MFA, Pattern)), + error_to_exit(p, dbg:p(all, [call, timestamp])) + catch + exit:{Where, Reason} -> + {error, {Where, Reason}} + end + end. + +error_to_exit(_Where, {ok, _} = OK) -> + OK; +error_to_exit(Where, {error, Reason}) -> + exit({Where, Reason}). + + +%%----------------------------------------------------------------- +%% report_event(Severity, Label, Service, Content) +%% +%% Parameters: +%% Severity -> 0 =< integer() =< 100 +%% Label -> string() +%% Service -> httpd | httpc | ftp | tftp +%% Content -> [{tag, term()}] +%% +%% Description: +%% This function is used to generate trace events, that is, +%% put trace on this function. +%%----------------------------------------------------------------- + +report_event(Severity, Label, Service, Content) + when (is_integer(Severity) andalso + (Severity >= 0) andalso (100 >= Severity)) andalso + is_list(Label) andalso + is_atom(Service) andalso + is_list(Content) -> + hopefully_traced. + + +%% ---------------------------------------------------------------------- +%% handle_trace(Event, Fd) -> Verbosity +%% +%% Parameters: +%% Event -> The trace event +%% Fd -> standard_io | file_descriptor() | trace_port() +%% +%% Description: +%% This function is used to "receive" and pretty print the trace events. +%% Events are printed if: +%% - Verbosity is max +%% - Severity is =< Verbosity (e.g. Severity = 30, and Verbosity = 40) +%% Events are not printed if: +%% - Verbosity is min +%% - Severity is > Verbosity +%%----------------------------------------------------------------- + +handle_trace(_, closed_file = Fd) -> + Fd; +handle_trace({trace_ts, _Who, call, + {?MODULE, report_event, + [_Sev, "stop trace", stop_trace, [stop_trace]]}, + Timestamp}, + {_, standard_io} = Fd) -> + (catch io:format(standard_io, "stop trace at ~s~n", [format_timestamp(Timestamp)])), + Fd; +handle_trace({trace_ts, _Who, call, + {?MODULE, report_event, + [_Sev, "stop trace", stop_trace, [stop_trace]]}, + Timestamp}, + standard_io = Fd) -> + (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), + Fd; +handle_trace({trace_ts, _Who, call, + {?MODULE, report_event, + [_Sev, "stop trace", stop_trace, [stop_trace]]}, + Timestamp}, + {_Service, Fd}) -> + (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), + (catch file:close(Fd)), + closed_file; +handle_trace({trace_ts, _Who, call, + {?MODULE, report_event, + [_Sev, "stop trace", stop_trace, [stop_trace]]}, + Timestamp}, + Fd) -> + (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), + (catch file:close(Fd)), + closed_file; +handle_trace({trace_ts, Who, call, + {?MODULE, report_event, + [Sev, Label, Service, Content]}, Timestamp}, + Fd) -> + (catch print_inets_trace(Fd, Sev, Timestamp, Who, + Label, Service, Content)), + Fd; +handle_trace(Event, Fd) -> + (catch print_trace(Fd, Event)), + Fd. + + +print_inets_trace({Service, Fd}, + Sev, Timestamp, Who, Label, Service, Content) -> + do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content); +print_inets_trace({ServiceA, Fd}, + Sev, Timestamp, Who, Label, ServiceB, Content) + when (ServiceA =:= all) -> + do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, ServiceB, Content); +print_inets_trace({ServiceA, _Fd}, + _Sev, _Timestamp, _Who, _Label, ServiceB, _Content) + when ServiceA =/= ServiceB -> + ok; +print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) -> + do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content). + +do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) -> + Ts = format_timestamp(Timestamp), + io:format(Fd, "[inets ~w trace ~w ~w ~s] ~s " + "~n Content: ~p" + "~n", + [Service, Sev, Who, Ts, Label, Content]). + +print_trace({_, Fd}, Event) -> + do_print_trace(Fd, Event); +print_trace(Fd, Event) -> + do_print_trace(Fd, Event). + +do_print_trace(Fd, {trace, Who, What, Where}) -> + io:format(Fd, "[trace]" + "~n Who: ~p" + "~n What: ~p" + "~n Where: ~p" + "~n", [Who, What, Where]); + +do_print_trace(Fd, {trace, Who, What, Where, Extra}) -> + io:format(Fd, "[trace]" + "~n Who: ~p" + "~n What: ~p" + "~n Where: ~p" + "~n Extra: ~p" + "~n", [Who, What, Where, Extra]); + +do_print_trace(Fd, {trace_ts, Who, What, Where, When}) -> + Ts = format_timestamp(When), + io:format(Fd, "[trace ~s]" + "~n Who: ~p" + "~n What: ~p" + "~n Where: ~p" + "~n", [Ts, Who, What, Where]); + +do_print_trace(Fd, {trace_ts, Who, What, Where, Extra, When}) -> + Ts = format_timestamp(When), + io:format(Fd, "[trace ~s]" + "~n Who: ~p" + "~n What: ~p" + "~n Where: ~p" + "~n Extra: ~p" + "~n", [Ts, Who, What, Where, Extra]); + +do_print_trace(Fd, {seq_trace, What, Where}) -> + io:format(Fd, "[seq trace]" + "~n What: ~p" + "~n Where: ~p" + "~n", [What, Where]); + +do_print_trace(Fd, {seq_trace, What, Where, When}) -> + Ts = format_timestamp(When), + io:format(Fd, "[seq trace ~s]" + "~n What: ~p" + "~n Where: ~p" + "~n", [Ts, What, Where]); + +do_print_trace(Fd, {drop, Num}) -> + io:format(Fd, "[drop trace] ~p~n", [Num]); + +do_print_trace(Fd, Trace) -> + io:format(Fd, "[trace] " + "~n ~p" + "~n", [Trace]). + + +format_timestamp({_N1, _N2, N3} = Now) -> + {Date, Time} = calendar:now_to_datetime(Now), + {YYYY,MM,DD} = Date, + {Hour,Min,Sec} = Time, + FormatDate = + io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w", + [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]), + lists:flatten(FormatDate). + + -- cgit v1.2.3 From 37b394fc0f7a6cb799f07d396b30983327df74fc Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 19 Dec 2011 13:04:38 +0100 Subject: [inets] Improved error handling in test case --- lib/inets/test/httpc_SUITE.erl | 67 ++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 3276481fed..c33ac12b66 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -245,31 +245,31 @@ init_per_testcase(Case, Timeout, Config) -> "~n~n*** INIT ~w:~w[~w] ***" "~n~n", [?MODULE, Case, Timeout]), - io:format("init_per_testcase(~w) -> entry with" - "~n Timeout: ~p" - "~n Config: ~p" - "~n" - "~nwhen" - "~n" - "~n OS Type: ~p" - "~n OS version: ~p" - "~n Sys Arch: ~p" - "~n CPU Topology: ~p" - "~n Num logical procs: ~p" - "~n SMP support: ~p" - "~n Num schedulers: ~p" - "~n Scheduler bindings: ~p" - "~n Wordsize: ~p" - "~n~n", [Case, Timeout, Config, - os:type(), os:version(), - erlang:system_info(system_architecture), - erlang:system_info(cpu_topology), - erlang:system_info(logical_processors), - erlang:system_info(smp_support), - erlang:system_info(schedulers), - erlang:system_info(scheduler_bindings), - erlang:system_info(wordsize)]), - + tsp("init_per_testcase(~w) -> entry with" + "~n Timeout: ~p" + "~n Config: ~p" + "~n" + "~nwhen" + "~n" + "~n OS Type: ~p" + "~n OS version: ~p" + "~n Sys Arch: ~p" + "~n CPU Topology: ~p" + "~n Num logical procs: ~p" + "~n SMP support: ~p" + "~n Num schedulers: ~p" + "~n Scheduler bindings: ~p" + "~n Wordsize: ~p" + "~n~n", [Case, Timeout, Config, + os:type(), os:version(), + erlang:system_info(system_architecture), + erlang:system_info(cpu_topology), + erlang:system_info(logical_processors), + erlang:system_info(smp_support), + erlang:system_info(schedulers), + erlang:system_info(scheduler_bindings), + erlang:system_info(wordsize)]), + PrivDir = ?config(priv_dir, Config), application:stop(inets), Dog = test_server:timetrap(inets_test_lib:minutes(Timeout)), @@ -1169,9 +1169,20 @@ ssl_get(SslTag, Config) when is_list(Config) -> "~n URL: ~p" "~n SslTag: ~p" "~n SSLOptions: ~p", [URL, SslTag, SSLOptions]), - {ok, {{_,200, _}, [_ | _], Body = [_ | _]}} = - httpc:request(get, {URL, []}, [{ssl, SSLConfig}], []), - inets_test_lib:check_body(Body); + case httpc:request(get, {URL, []}, [{ssl, SSLConfig}], []) of + {ok, {{_,200, _}, [_ | _], Body = [_ | _]}} -> + inets_test_lib:check_body(Body), + ok; + {ok, {StatusLine, Headers, _Body}} -> + tsp("ssl_get -> unexpected result: " + "~n StatusLine: ~p" + "~n Headers: ~p", [StatusLine, Headers]), + tsf({unexpected_response, StatusLine, Headers}); + {error, Reason} -> + tsp("ssl_get -> request failed: " + "~n Reason: ~p", [Reason]), + tsf({request_failed, Reason}) + end; {ok, _} -> {skip, "local http-server not started"}; _ -> -- cgit v1.2.3 From d012c3ca920a2bfb487b4973601d92e92591d48f Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 19 Dec 2011 15:14:09 +0100 Subject: [inets] Added verbosity printout to improve error detection Added verbosity printouts to detect error reason for file access error on windows. --- lib/inets/src/http_server/mod_get.erl | 16 ++++++++++++---- lib/inets/test/httpd_basic_SUITE.erl | 12 ++++++------ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/lib/inets/src/http_server/mod_get.erl b/lib/inets/src/http_server/mod_get.erl index 5cb30e3d97..c58d1f3508 100644 --- a/lib/inets/src/http_server/mod_get.erl +++ b/lib/inets/src/http_server/mod_get.erl @@ -18,9 +18,16 @@ %% %% -module(mod_get). + -export([do/1]). + -include("httpd.hrl"). -include("httpd_internal.hrl"). +-include("inets_internal.hrl"). + +-define(VMODULE,"GET"). + + %% do do(Info) -> @@ -84,15 +91,16 @@ send_response(_Socket, _SocketType, Path, Info)-> file:close(FileDescriptor), {proceed,[{response,{already_sent,200, FileInfo#file_info.size}}, - {mime_type,MimeType}|Info#mod.data]}; + {mime_type,MimeType} | Info#mod.data]}; {error, Reason} -> + ?hdrt("send_response -> failed open file", + [{path, Path}, {reason, Reason}]), Status = httpd_file:handle_error(Reason, "open", Info, Path), - {proceed, - [{status, Status}| Info#mod.data]} + {proceed, [{status, Status} | Info#mod.data]} end. %% send - + send(#mod{socket = Socket, socket_type = SocketType} = Info, StatusCode, Headers, FileDescriptor) -> ?DEBUG("send -> send header",[]), diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl index 4cd38f2ec4..be0bcc67d5 100644 --- a/lib/inets/test/httpd_basic_SUITE.erl +++ b/lib/inets/test/httpd_basic_SUITE.erl @@ -202,8 +202,8 @@ escaped_url_in_error_body(Config) when is_list(Config) -> {ok, {200, _}} -> %% Don't care about the the body, just that we get a ok response ok; - {ok, UnexpectedOK1} -> - tsf({unexpected_ok_1, UnexpectedOK1}) + {ok, {StatusCode1, Body1}} -> + tsf({unexpected_ok_1, StatusCode1, Body1}) end, %% Request 2 @@ -216,8 +216,8 @@ escaped_url_in_error_body(Config) when is_list(Config) -> {ok, {200, _}} -> %% Don't care about the the body, just that we get a ok response ok; - {ok, UnexpectedOK2} -> - tsf({unexpected_ok_2, UnexpectedOK2}) + {ok, {StatusCode2, Body2}} -> + tsf({unexpected_ok_2, StatusCode2, Body2}) end, %% Request 3 @@ -238,7 +238,7 @@ escaped_url_in_error_body(Config) when is_list(Config) -> tsf({unexpected_path_3, HTMLEncodedPath, BadPath3}) end; {ok, UnexpectedOK3} -> - tsf({unexpected_ok_1, UnexpectedOK3}) + tsf({unexpected_ok_3, UnexpectedOK3}) end, %% Request 4 @@ -253,7 +253,7 @@ escaped_url_in_error_body(Config) when is_list(Config) -> HTMLEncodedPath -> ok; BadPath4 -> - tsf({unexpected_path_2, HTMLEncodedPath, BadPath4}) + tsf({unexpected_path_4, HTMLEncodedPath, BadPath4}) end; {ok, UnexpectedOK4} -> tsf({unexpected_ok_4, UnexpectedOK4}) -- cgit v1.2.3 From d36414e480a69ae5f36b057e8cd6903d4a2f59c6 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 20 Dec 2011 12:43:05 +0100 Subject: [inets] Testing IPv6 support on windows... --- lib/inets/test/httpc_SUITE.erl | 37 ++++++++----------------------------- lib/inets/test/httpd_mod.erl | 23 +++++++++++++++++------ lib/inets/test/httpd_test_lib.erl | 22 +++++++++++----------- lib/inets/test/inets_test_lib.hrl | 5 +++++ 4 files changed, 41 insertions(+), 46 deletions(-) diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index c33ac12b66..089e0766cb 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -245,30 +245,7 @@ init_per_testcase(Case, Timeout, Config) -> "~n~n*** INIT ~w:~w[~w] ***" "~n~n", [?MODULE, Case, Timeout]), - tsp("init_per_testcase(~w) -> entry with" - "~n Timeout: ~p" - "~n Config: ~p" - "~n" - "~nwhen" - "~n" - "~n OS Type: ~p" - "~n OS version: ~p" - "~n Sys Arch: ~p" - "~n CPU Topology: ~p" - "~n Num logical procs: ~p" - "~n SMP support: ~p" - "~n Num schedulers: ~p" - "~n Scheduler bindings: ~p" - "~n Wordsize: ~p" - "~n~n", [Case, Timeout, Config, - os:type(), os:version(), - erlang:system_info(system_architecture), - erlang:system_info(cpu_topology), - erlang:system_info(logical_processors), - erlang:system_info(smp_support), - erlang:system_info(schedulers), - erlang:system_info(scheduler_bindings), - erlang:system_info(wordsize)]), + ?PRINT_SYSTEM_INFO("init_per_testcase"), PrivDir = ?config(priv_dir, Config), application:stop(inets), @@ -382,8 +359,10 @@ init_per_testcase(Case, Timeout, Config) -> _ -> %% Try inet6fb4 on windows... - %% ...but since I dont know exactly how to test this... - %% ...this should also effect the server... + ?RUN_ON_WINDOWS( + fun() -> + httpc:set_options([{ipfamily, inet6fb4}]) + end), TmpConfig2 = lists:keydelete(local_server, 1, TmpConfig), %% Will start inets @@ -397,9 +376,9 @@ init_per_testcase(Case, Timeout, Config) -> inets:enable_trace(max, io, httpc), %% inets:enable_trace(max, io, all), %% snmp:set_trace([gen_tcp]), - io:format("init_per_testcase(~w) -> done when" - "~n NewConfig: ~p" - "~n~n", [Case, NewConfig]), + tsp("init_per_testcase(~w) -> done when" + "~n NewConfig: ~p" + "~n~n", [Case, NewConfig]), NewConfig. diff --git a/lib/inets/test/httpd_mod.erl b/lib/inets/test/httpd_mod.erl index 5016cdb9e6..6ba0624210 100644 --- a/lib/inets/test/httpd_mod.erl +++ b/lib/inets/test/httpd_mod.erl @@ -39,14 +39,25 @@ %% Test cases starts here. %%------------------------------------------------------------------------- alias(Type, Port, Host, Node) -> -%% io:format(user, "~w:alias -> entry with" + %% io:format(user, "~w:alias -> entry with" %% "~n Type: ~p" %% "~n Port: ~p" %% "~n Host: ~p" %% "~n Node: ~p" %% "~n", [?MODULE, Type, Port, Host, Node]), + + %% This is very crude, but... + io:format(user, + "alias -> Has IPv6 support: ~p", + [inets_test_lib:has_ipv6_support()]), + Opts = case os:type() of + {win32, _} -> + [inet6fb4]; + _ -> + [] + end, - ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + ok = httpd_test_lib:verify_request(Type, Host, Port, Opts, Node, "GET /pics/icon.sheet.gif " "HTTP/1.0\r\n\r\n", [{statuscode, 200}, @@ -55,7 +66,7 @@ alias(Type, Port, Host, Node) -> {header, "Date"}, {version, "HTTP/1.0"}]), - ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + ok = httpd_test_lib:verify_request(Type, Host, Port, Opts, Node, "GET / HTTP/1.0\r\n\r\n", [{statuscode, 200}, {header, "Content-Type","text/html"}, @@ -63,7 +74,7 @@ alias(Type, Port, Host, Node) -> {header, "Date"}, {version, "HTTP/1.0"}]), - ok = httpd_test_lib:verify_request(Type,Host,Port,Node, + ok = httpd_test_lib:verify_request(Type, Host, Port, Opts, Node, "GET /misc/ HTTP/1.0\r\n\r\n", [{statuscode, 200}, {header, "Content-Type","text/html"}, @@ -71,8 +82,8 @@ alias(Type, Port, Host, Node) -> {header, "Date"}, {version, "HTTP/1.0"}]), - %% Check redirection if trailing slash is missing. - ok = httpd_test_lib:verify_request(Type,Host,Port,Node, + %% Check redirection if trailing slash is missing. + ok = httpd_test_lib:verify_request(Type, Host, Port, Opts, Node, "GET /misc HTTP/1.0\r\n\r\n", [{statuscode, 301}, {header, "Location"}, diff --git a/lib/inets/test/httpd_test_lib.erl b/lib/inets/test/httpd_test_lib.erl index 2f5867559a..ed6ee315b3 100644 --- a/lib/inets/test/httpd_test_lib.erl +++ b/lib/inets/test/httpd_test_lib.erl @@ -79,19 +79,19 @@ %%-------------------------------------------------------------------- %% API %%------------------------------------------------------------------ + verify_request(SocketType, Host, Port, Node, RequestStr, Options) -> - verify_request(SocketType, Host, Port, Node, RequestStr, - Options, 30000). + verify_request(SocketType, Host, Port, Node, RequestStr, Options, 30000). + verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options) when is_list(TranspOpts) -> - verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, - Options, 30000); + verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options, 30000); + verify_request(SocketType, Host, Port, Node, RequestStr, Options, TimeOut) when (is_integer(TimeOut) orelse (TimeOut =:= infinity)) -> - verify_request(SocketType, Host, Port, [], Node, RequestStr, - Options, TimeOut). -verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, - Options, TimeOut) -> + verify_request(SocketType, Host, Port, [], Node, RequestStr, Options, TimeOut). + +verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options, TimeOut) -> tsp("verify_request -> entry with" "~n SocketType: ~p" "~n Host: ~p" @@ -117,15 +117,15 @@ verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, case request(State#state{request = RequestStr, socket = Socket}, TimeOut) of {error, Reason} -> - tsp("request failed: " + tsp("verify_request -> request failed: " "~n Reason: ~p", [Reason]), {error, Reason}; NewState -> - tsp("validate reply: " + tsp("verify_request -> validate reply: " "~n NewState: ~p", [NewState]), ValidateResult = validate(RequestStr, NewState, Options, Node, Port), - tsp("validation result: " + tsp("verify_request -> validation result: " "~n ~p", [ValidateResult]), inets_test_lib:close(SocketType, Socket), ValidateResult diff --git a/lib/inets/test/inets_test_lib.hrl b/lib/inets/test/inets_test_lib.hrl index c578398c55..6a86b1b764 100644 --- a/lib/inets/test/inets_test_lib.hrl +++ b/lib/inets/test/inets_test_lib.hrl @@ -50,6 +50,11 @@ -define(OSCMD(Cmd), inets_test_lib:oscmd(Cmd)). +-define(PRINT_SYSTEM_INFO(P), inets_test_lib:print_system_info(P)). + +-define(RUN_ON_OS(OS, FUN), inets_test_lib:run_on_os(OS, FUN)). +-define(RUN_ON_WINDOWS(FUN), inets_test_lib:run_on_windows(FUN)). + %% - Test case macros - -- cgit v1.2.3 From 7b8fa1f43cf92e95eb3c899fdc0dcb7efe6c16b5 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 20 Dec 2011 17:54:48 +0100 Subject: [inets] Conditionally exec functions, testing for local host IPv6 support --- lib/inets/test/inets_test_lib.erl | 176 +++++++++++++++++++++++++++----------- 1 file changed, 126 insertions(+), 50 deletions(-) diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl index bbed35e1f8..38ffcdc226 100644 --- a/lib/inets/test/inets_test_lib.erl +++ b/lib/inets/test/inets_test_lib.erl @@ -34,7 +34,8 @@ -export([tsp/1, tsp/2, tsf/1]). -export([check_body/1]). -export([millis/0, millis_diff/2, hours/1, minutes/1, seconds/1, sleep/1]). --export([oscmd/1, has_ipv6_support/1]). +-export([oscmd/1, has_ipv6_support/0, has_ipv6_support/1, print_system_info/1]). +-export([run_on_os/2, run_on_windows/1]). -export([ensure_started/1]). -export([non_pc_tc_maybe_skip/4, os_based_skip/1, skip/3, fail/3]). -export([flush/0]). @@ -42,31 +43,35 @@ %% -- Misc os command and stuff +has_ipv6_support() -> + tsp("has_ipv6_support -> no ipv6_hosts config"), + {ok, Hostname} = inet:gethostname(), + case inet:getaddrs(Hostname, inet6) of + {ok, [Addr|_]} when is_tuple(Addr) andalso + (element(1, Addr) =/= 0) -> + %% We actually need to test that the addr can be used, + %% this is done by attempting to create a (tcp) + %% listen socket + tsp("has_ipv6_support -> check Addr: ~p", [Addr]), + case (catch gen_tcp:listen(0, [inet6, {ip, Addr}])) of + {ok, LSock} -> + tsp("has_ipv6_support -> we are ipv6 host"), + gen_tcp:close(LSock), + {ok, Addr}; + _ -> + undefined + end; + _ -> + undefined + end. + has_ipv6_support(Config) -> case lists:keysearch(ipv6_hosts, 1, Config) of false -> %% Do a basic check to se if %% our own host has a working IPv6 address... - tsp("has_ipv6_support -> no ipv6_hosts config"), - {ok, Hostname} = inet:gethostname(), - case inet:getaddrs(Hostname, inet6) of - {ok, [Addr|_]} when is_tuple(Addr) andalso - (element(1, Addr) =/= 0) -> - %% We actually need to test that the addr can be used, - %% this is done by attempting to create a (tcp) - %% listen socket - tsp("has_ipv6_support -> check Addr: ~p", [Addr]), - case (catch gen_tcp:listen(0, [inet6, {ip, Addr}])) of - {ok, LSock} -> - tsp("has_ipv6_support -> we are ipv6 host"), - gen_tcp:close(LSock), - {ok, Addr}; - _ -> - undefined - end; - _ -> - undefined - end; + has_ipv6_support(); + {value, {_, Hosts}} when is_list(Hosts) -> %% Check if our host is in the list of *known* IPv6 hosts tsp("has_ipv6_support -> Hosts: ~p", [Hosts]), @@ -88,6 +93,49 @@ has_ipv6_support(Config) -> oscmd(Cmd) -> string:strip(os:cmd(Cmd), right, $\n). + +print_system_info([]) -> + do_print_system_info("System Info"); +print_system_info(Prefix) when is_list(Prefix) -> + NewPrefix = lists:flatten(io_lib:format("~s: System Info", [Prefix])), + do_print_system_info(NewPrefix). + +do_print_system_info(Prefix) -> + tsp("~s => " + "~n" + "~n OS Type: ~p" + "~n OS version: ~p" + "~n Sys Arch: ~p" + "~n CPU Topology: ~p" + "~n Num logical procs: ~p" + "~n SMP support: ~p" + "~n Num schedulers: ~p" + "~n Scheduler bindings: ~p" + "~n Wordsize: ~p" + "~n~n", [Prefix, + os:type(), os:version(), + erlang:system_info(system_architecture), + erlang:system_info(cpu_topology), + erlang:system_info(logical_processors), + erlang:system_info(smp_support), + erlang:system_info(schedulers), + erlang:system_info(scheduler_bindings), + erlang:system_info(wordsize)]), + ok. + + +run_on_windows(Fun) -> + run_on_os(windows, Fun). + +run_on_os(windows, Fun) -> + case os:type() of + {win32, _} -> + Fun(); + _ -> + ok + end. + + %% -- Misc node operation wrapper functions -- start_node(Name) -> @@ -414,36 +462,64 @@ connect(ip_comm, Host, Port, Opts) -> "~n Host: ~p" "~n Port: ~p" "~n Opts: ~p", [Host, Port, Opts]), - case gen_tcp:connect(Host,Port, Opts) of - {ok, Socket} -> - tsp("connect success"), - {ok, Socket}; - {error, nxdomain} -> - tsp("connect error nxdomain when opts: ~p", [Opts]), - connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); - {error, eafnosupport} -> - tsp("connect error eafnosupport when opts: ~p", [Opts]), - connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); - {error, econnreset} -> - tsp("connect error econnreset when opts: ~p", [Opts]), - connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); - {error, enetunreach} -> - tsp("connect error eafnosupport when opts: ~p", [Opts]), - connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); - {error, {enfile,_}} -> - tsp("connect error enfile when opts: ~p", [Opts]), - {error, enfile}; - Error -> - tsp("Unexpected error: " - "~n Error: ~p" - "~nwhen" - "~n Host: ~p" - "~n Port: ~p" - "~n Opts: ~p" - "~n", [Error, Host, Port, Opts]), - Error - end. + + %% We check for precence of inet6fb4. + %% If found, we shall try inet6 and if that does not work + %% try inet (regardless of error reason) + case lists:delete(inet6fb4, Opts) of + Opts -> + %% Nope, run as usual, where we use error reason + %% to detect if we are on IPv6 or not... + case gen_tcp:connect(Host,Port, Opts) of + {ok, Socket} -> + tsp("connect success"), + {ok, Socket}; + {error, nxdomain} -> + tsp("connect error nxdomain when opts: ~p", [Opts]), + connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); + {error, eafnosupport} -> + tsp("connect error eafnosupport when opts: ~p", [Opts]), + connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); + {error, econnreset} -> + tsp("connect error econnreset when opts: ~p", [Opts]), + connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); + {error, enetunreach} -> + tsp("connect error eafnosupport when opts: ~p", [Opts]), + connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); + {error, {enfile,_}} -> + tsp("connect error enfile when opts: ~p", [Opts]), + {error, enfile}; + Error -> + tsp("connect(ip_conn) -> Unexpected error: " + "~n Error: ~p" + "~nwhen" + "~n Host: ~p" + "~n Port: ~p" + "~n Opts: ~p" + "~n", [Error, Host, Port, Opts]), + Error + end; + Opts2 -> + %% Yep, so try first with inet6 and if that fails inet + case gen_tcp:connect(Host, Port, [inet6|Opts2]) of + {ok, Socket} -> + tsp("connect success"), + {ok, Socket}; + {error, Reason_inet6} -> + tsp("inet6 connect failed: ~p", [Reason_inet6]), + case gen_tcp:connect(Host, Port, [inet|Opts2]) of + {ok, Socket} -> + tsp("connect success"), + {ok, Socket}; + {error, Reason_inet} -> + tsp("inet connect also failed: ~p", [Reason_inet]), + {error, {connect_failure, [{inet6, Reason_inet6}, + {inet, Reason_inet}]}} + end + end + end. + send(ssl, Socket, Data) -> ssl:send(Socket, Data); -- cgit v1.2.3 From 8d6b47823001de84b09062baee10b7ed7e3f8864 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 21 Dec 2011 11:07:16 +0100 Subject: [inets] Add preliminary "has IPv6 support" info to TC config --- lib/inets/test/httpc_SUITE.erl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 089e0766cb..81a1fdab4e 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -179,10 +179,11 @@ init_per_suite(Config) -> {ok, FileInfo} = file:read_file_info(Cgi), ok = file:write_file_info(Cgi, FileInfo#file_info{mode = 8#00755}), - [{server_root, ServerRoot}, - {doc_root, DocRoot}, - {local_port, ?IP_PORT}, - {local_ssl_port, ?SSL_PORT} | Config]. + [{server_root, ServerRoot}, + {has_ipv6_support, inets_test_lib:has_ipv6_support()}, + {doc_root, DocRoot}, + {local_port, ?IP_PORT}, + {local_ssl_port, ?SSL_PORT} | Config]. %%-------------------------------------------------------------------- -- cgit v1.2.3 From 67b0023a0756c69f58a40702ed9a808e1e5a66a7 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 21 Dec 2011 14:32:55 +0100 Subject: [inets] System Info printouts in test suite Moved the System Info printout to the init_per_suite function for the httpc suite. Added it to the same function for the httpd suite. --- lib/inets/test/httpc_SUITE.erl | 10 ++++++---- lib/inets/test/httpd_SUITE.erl | 2 ++ lib/inets/test/inets_test_lib.erl | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 81a1fdab4e..8cce152697 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -156,6 +156,9 @@ groups() -> %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- init_per_suite(Config) -> + + ?PRINT_SYSTEM_INFO([]), + PrivDir = ?config(priv_dir, Config), DataDir = ?config(data_dir, Config), ServerRoot = filename:join(PrivDir, "server_root"), @@ -179,8 +182,8 @@ init_per_suite(Config) -> {ok, FileInfo} = file:read_file_info(Cgi), ok = file:write_file_info(Cgi, FileInfo#file_info{mode = 8#00755}), - [{server_root, ServerRoot}, - {has_ipv6_support, inets_test_lib:has_ipv6_support()}, + [{has_ipv6_support, inets_test_lib:has_ipv6_support()}, + {server_root, ServerRoot}, {doc_root, DocRoot}, {local_port, ?IP_PORT}, {local_ssl_port, ?SSL_PORT} | Config]. @@ -199,6 +202,7 @@ end_per_suite(Config) -> application:stop(ssl), ok. + %%-------------------------------------------------------------------- %% Function: init_per_testcase(Case, Config) -> Config %% Case - atom() @@ -246,8 +250,6 @@ init_per_testcase(Case, Timeout, Config) -> "~n~n*** INIT ~w:~w[~w] ***" "~n~n", [?MODULE, Case, Timeout]), - ?PRINT_SYSTEM_INFO("init_per_testcase"), - PrivDir = ?config(priv_dir, Config), application:stop(inets), Dog = test_server:timetrap(inets_test_lib:minutes(Timeout)), diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index a4bb8f7159..2c4c0f84a8 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -314,6 +314,8 @@ init_per_suite(Config) -> "~n Config: ~p" "~n", [Config]), + ?PRINT_SYSTEM_INFO([]), + PrivDir = ?config(priv_dir, Config), SuiteTopDir = filename:join(PrivDir, ?MODULE), case file:make_dir(SuiteTopDir) of diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl index 38ffcdc226..434fa17307 100644 --- a/lib/inets/test/inets_test_lib.erl +++ b/lib/inets/test/inets_test_lib.erl @@ -41,6 +41,7 @@ -export([flush/0]). -export([start_node/1, stop_node/1]). + %% -- Misc os command and stuff has_ipv6_support() -> -- cgit v1.2.3 From 0d580acdc51bd88a0d364b76ac35fcf2506c2d9e Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 22 Dec 2011 12:00:55 +0100 Subject: [inets] Improved test util error handling when copy dirs Copy dirs failed for some cases, so added more info when that happens. Also added more info during httpd test case init. --- lib/inets/test/httpc_SUITE.erl | 88 ++++++++++++++++++++------- lib/inets/test/httpd_SUITE.erl | 122 ++++++++++++++++++-------------------- lib/inets/test/httpd_mod.erl | 14 ++--- lib/inets/test/inets_test_lib.erl | 57 +++++++++++++----- 4 files changed, 175 insertions(+), 106 deletions(-) diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 8cce152697..734964698e 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -362,9 +362,15 @@ init_per_testcase(Case, Timeout, Config) -> _ -> %% Try inet6fb4 on windows... + tsp("init_per_testcase -> allways try IPv6 on windows"), ?RUN_ON_WINDOWS( fun() -> - httpc:set_options([{ipfamily, inet6fb4}]) + tsp("init_per_testcase:set_options_fun -> " + "set-option ipfamily to inet6fb4"), + Res = httpc:set_options([{ipfamily, inet6fb4}]), + tsp("init_per_testcase:set_options_fun -> " + "~n Res: ~p", [Res]), + Res end), TmpConfig2 = lists:keydelete(local_server, 1, TmpConfig), @@ -471,22 +477,32 @@ http_head(doc) -> http_head(suite) -> []; http_head(Config) when is_list(Config) -> - case ?config(local_server, Config) of - ok -> - Port = ?config(local_port, Config), - URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", - case httpc:request(head, {URL, []}, [], []) of - {ok, {{_,200,_}, [_ | _], []}} -> - ok; - {ok, WrongReply} -> - tsf({wrong_reply, WrongReply}); - Error -> - tsf({failed, Error}) - end; - _ -> - {skip, "Failed to start local http-server"} - end. + tsp("http_head -> entry with" + "~n Config: ~p", [Config]), + Method = head, + Port = ?config(local_port, Config), + URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", + Request = {URL, []}, + HttpOpts = [], + Opts = [], + VerifyResult = + fun({ok, {{_,200,_}, [_ | _], []}}) -> + ok; + ({ok, UnexpectedReply}) -> + tsp("http_head:verify_fun -> Unexpected Reply: " + "~n ~p", [UnexpectedReply]), + tsf({unexpected_reply, UnexpectedReply}); + ({error, Reason} = Error) -> + tsp("http_head:verify_fun -> Error reply: " + "~n Reason: ~p", [Reason]), + tsf({bad_reply, Error}) + end, + simple_request_and_verify(Config, + Method, Request, HttpOpts, Opts, VerifyResult). + + %%------------------------------------------------------------------------- + http_get(doc) -> ["Test http get request against local server"]; http_get(suite) -> @@ -503,7 +519,8 @@ http_get(Config) when is_list(Config) -> Request = {URL, []}, Timeout = timer:seconds(1), ConnTimeout = Timeout + timer:seconds(1), - HttpOptions1 = [{timeout, Timeout}, {connect_timeout, ConnTimeout}], + HttpOptions1 = [{timeout, Timeout}, + {connect_timeout, ConnTimeout}], Options1 = [], Body = case httpc:request(Method, Request, HttpOptions1, Options1) of @@ -535,10 +552,11 @@ http_get(Config) when is_list(Config) -> end. %%------------------------------------------------------------------------- + http_post(doc) -> - ["Test http post request against local server. We do in this case" - " only care about the client side of the the post. The server" - " script will not actually use the post data."]; + ["Test http post request against local server. We do in this case " + "only care about the client side of the the post. The server " + "script will not actually use the post data."]; http_post(suite) -> []; http_post(Config) when is_list(Config) -> @@ -3839,6 +3857,34 @@ pick_header(Headers, Name) -> Val end. + +%% ------------------------------------------------------------------------- + +simple_request_and_verify(Config, + Method, Request, HttpOpts, Opts, VerifyResult) + when (is_list(Config) andalso + is_atom(Method) andalso + is_list(HttpOpts) andalso + is_list(Opts) andalso + is_function(VerifyResult, 1)) -> + tsp("request_and_verify -> entry with" + "~n Method: ~p" + "~n Request: ~p" + "~n HttpOpts: ~p" + "~n Opts: ~p", [Method, Request, HttpOpts, Opts]), + case ?config(local_server, Config) of + ok -> + tsp("request_and_verify -> local-server running"), + Result = (catch httpc:request(Method, Request, HttpOpts, Opts)), + VerifyResult(Result); + _ -> + tsp("request_and_verify -> local-server *not* running - skip"), + hard_skip("Local http-server not running") + end. + + + + not_implemented_yet() -> exit(not_implemented_yet). @@ -3890,6 +3936,8 @@ dummy_ssl_server_hang_loop(_) -> ok end. +hard_skip(Reason) -> + throw(skip(Reason)). skip(Reason) -> {skip, Reason}. diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index 2c4c0f84a8..907d58fd8c 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -327,10 +327,11 @@ init_per_suite(Config) -> throw({error, {failed_creating_suite_top_dir, Error}}) end, - [{suite_top_dir, SuiteTopDir}, - {node, node()}, - {host, inets_test_lib:hostname()}, - {address, getaddr()} | Config]. + [{has_ipv6_support, inets_test_lib:has_ipv6_support()}, + {suite_top_dir, SuiteTopDir}, + {node, node()}, + {host, inets_test_lib:hostname()}, + {address, getaddr()} | Config]. %%-------------------------------------------------------------------- @@ -365,10 +366,9 @@ init_per_testcase(Case, Config) -> init_per_testcase2(Case, Config) -> - io:format(user, "~w:init_per_testcase2(~w) -> entry with" - "~n Config: ~p" - "~n", [?MODULE, Case, Config]), - + tsp("init_per_testcase2(~w) -> entry with" + "~n Config: ~p", [Case, Config]), + IpNormal = integer_to_list(?IP_PORT) ++ ".conf", IpHtaccess = integer_to_list(?IP_PORT) ++ "htaccess.conf", SslNormal = integer_to_list(?SSL_PORT) ++ ".conf", @@ -377,39 +377,33 @@ init_per_testcase2(Case, Config) -> DataDir = ?config(data_dir, Config), SuiteTopDir = ?config(suite_top_dir, Config), - io:format(user, "~w:init_per_testcase2(~w) -> " - "~n SuiteDir: ~p" - "~n DataDir: ~p" - "~n", [?MODULE, Case, SuiteTopDir, DataDir]), + tsp("init_per_testcase2(~w) -> " + "~n SuiteDir: ~p" + "~n DataDir: ~p", [Case, SuiteTopDir, DataDir]), TcTopDir = filename:join(SuiteTopDir, Case), ?line ok = file:make_dir(TcTopDir), - io:format(user, "~w:init_per_testcase2(~w) -> " - "~n TcTopDir: ~p" - "~n", [?MODULE, Case, TcTopDir]), + tsp("init_per_testcase2(~w) -> " + "~n TcTopDir: ~p", [Case, TcTopDir]), DataSrc = filename:join([DataDir, "server_root"]), ServerRoot = filename:join([TcTopDir, "server_root"]), - io:format(user, "~w:init_per_testcase2(~w) -> " - "~n DataSrc: ~p" - "~n ServerRoot: ~p" - "~n", [?MODULE, Case, DataSrc, ServerRoot]), + tsp("init_per_testcase2(~w) -> " + "~n DataSrc: ~p" + "~n ServerRoot: ~p", [Case, DataSrc, ServerRoot]), ok = file:make_dir(ServerRoot), ok = file:make_dir(filename:join([TcTopDir, "logs"])), NewConfig = [{tc_top_dir, TcTopDir}, {server_root, ServerRoot} | Config], - io:format(user, "~w:init_per_testcase2(~w) -> " - "copy DataSrc to ServerRoot~n", - [?MODULE, Case]), + tsp("init_per_testcase2(~w) -> copy DataSrc to ServerRoot", [Case]), inets_test_lib:copy_dirs(DataSrc, ServerRoot), - io:format(user, "~w:init_per_testcase2(~w) -> fix cgi~n", - [?MODULE, Case]), + tsp("init_per_testcase2(~w) -> fix cgi", [Case]), EnvCGI = filename:join([ServerRoot, "cgi-bin", "printenv.sh"]), {ok, FileInfo} = file:read_file_info(EnvCGI), ok = file:write_file_info(EnvCGI, @@ -429,16 +423,14 @@ init_per_testcase2(Case, Config) -> FileInfo1#file_info{mode = 8#00755}), %% To be used by IP test cases - io:format(user, "~w:init_per_testcase2(~w) -> ip testcase setups~n", - [?MODULE, Case]), + tsp("init_per_testcase2(~w) -> ip testcase setups", [Case]), create_config([{port, ?IP_PORT}, {sock_type, ip_comm} | NewConfig], normal_access, IpNormal), create_config([{port, ?IP_PORT}, {sock_type, ip_comm} | NewConfig], mod_htaccess, IpHtaccess), %% To be used by SSL test cases - io:format(user, "~w:init_per_testcase2(~w) -> ssl testcase setups~n", - [?MODULE, Case]), + tsp("init_per_testcase2(~w) -> ssl testcase setups", [Case]), SocketType = case atom_to_list(Case) of [X, $s, $s, $l | _] -> @@ -462,8 +454,7 @@ init_per_testcase2(Case, Config) -> %% when you run the whole test suite due to shortcomings %% of the test server. - io:format(user, "~w:init_per_testcase2(~w) -> " - "maybe generate IPv6 config file(s)", [?MODULE, Case]), + tsp("init_per_testcase2(~w) -> maybe generate IPv6 config file(s)", [Case]), NewConfig2 = case atom_to_list(Case) of "ipv6_" ++ _ -> @@ -504,15 +495,15 @@ init_per_testcase2(Case, Config) -> NewConfig end, - io:format(user, "~w:init_per_testcase2(~w) -> done~n", - [?MODULE, Case]), + tsp("init_per_testcase2(~w) -> done when" + "~n NewConfig2: ~p", [Case, NewConfig2]), NewConfig2. init_per_testcase3(Case, Config) -> - io:format(user, "~w:init_per_testcase3(~w) -> entry with" - "~n Config: ~p", [?MODULE, Case, Config]), + tsp("init_per_testcase3(~w) -> entry with" + "~n Config: ~p", [Case, Config]), %% %% Create a new fresh node to be used by the server in this test-case @@ -534,12 +525,10 @@ init_per_testcase3(Case, Config) -> %% Set trace level case lists:reverse(atom_to_list(Case)) of "tset_emit" ++ _Rest -> % test-cases ending with time_test - io:format(user, "~w:init_per_testcase3(~w) -> disabling trace", - [?MODULE, Case]), + tsp("init_per_testcase3(~w) -> disabling trace", [Case]), inets:disable_trace(); _ -> - io:format(user, "~w:init_per_testcase3(~w) -> enabling trace", - [?MODULE, Case]), + tsp("init_per_testcase3(~w) -> enabling trace", [Case]), %% TraceLevel = 70, TraceLevel = max, TraceDest = io, @@ -547,8 +536,7 @@ init_per_testcase3(Case, Config) -> end, %% Start initialization - io:format(user, "~w:init_per_testcase3(~w) -> start init", - [?MODULE, Case]), + tsp("init_per_testcase3(~w) -> start init", [Case]), Dog = test_server:timetrap(inets_test_lib:minutes(10)), @@ -629,26 +617,32 @@ init_per_testcase3(Case, Config) -> end end, - case CaseRest of - {skip, _} = Skip -> - Skip; - "mod_auth_" ++ _ -> - start_mnesia(?config(node, Config)), - [{watchdog, Dog} | NewConfig]; - "mod_htaccess" -> - ServerRoot = ?config(server_root, Config), - Path = filename:join([ServerRoot, "htdocs"]), - catch remove_htaccess(Path), - create_htaccess_data(Path, ?config(address, Config)), - [{watchdog, Dog} | NewConfig]; - "range" -> - ServerRoot = ?config(server_root, Config), - Path = filename:join([ServerRoot, "htdocs"]), - create_range_data(Path), - [{watchdog, Dog} | NewConfig]; - _ -> - [{watchdog, Dog} | NewConfig] - end. + InitRes = + case CaseRest of + {skip, _} = Skip -> + Skip; + "mod_auth_" ++ _ -> + start_mnesia(?config(node, Config)), + [{watchdog, Dog} | NewConfig]; + "mod_htaccess" -> + ServerRoot = ?config(server_root, Config), + Path = filename:join([ServerRoot, "htdocs"]), + catch remove_htaccess(Path), + create_htaccess_data(Path, ?config(address, Config)), + [{watchdog, Dog} | NewConfig]; + "range" -> + ServerRoot = ?config(server_root, Config), + Path = filename:join([ServerRoot, "htdocs"]), + create_range_data(Path), + [{watchdog, Dog} | NewConfig]; + _ -> + [{watchdog, Dog} | NewConfig] + end, + + tsp("init_per_testcase3(~w) -> done when" + "~n InitRes: ~p", [Case, InitRes]), + + InitRes. %%-------------------------------------------------------------------- @@ -666,16 +660,14 @@ end_per_testcase(Case, Config) -> ok. end_per_testcase2(Case, Config) -> - io:format(user, "~w:end_per_testcase2(~w) -> entry with" - "~n Config: ~p~n", - [?MODULE, Case, Config]), + tsp("end_per_testcase2(~w) -> entry with" + "~n Config: ~p", [Case, Config]), application:unset_env(inets, services), application:stop(inets), application:stop(ssl), application:stop(crypto), % used by the new ssl (essl test cases) cleanup_mnesia(), - io:format(user, "~w:end_per_testcase2(~w) -> done~n", - [?MODULE, Case]), + tsp("end_per_testcase2(~w) -> done", [Case]), ok. diff --git a/lib/inets/test/httpd_mod.erl b/lib/inets/test/httpd_mod.erl index 6ba0624210..25a03ab9c8 100644 --- a/lib/inets/test/httpd_mod.erl +++ b/lib/inets/test/httpd_mod.erl @@ -47,16 +47,15 @@ alias(Type, Port, Host, Node) -> %% "~n", [?MODULE, Type, Port, Host, Node]), %% This is very crude, but... - io:format(user, - "alias -> Has IPv6 support: ~p", - [inets_test_lib:has_ipv6_support()]), + tsp("alias -> Has IPv6 support: ~p", [inets_test_lib:has_ipv6_support()]), Opts = case os:type() of {win32, _} -> [inet6fb4]; _ -> [] end, - + tsp("alias -> Opts: ~p", [Opts]), + ok = httpd_test_lib:verify_request(Type, Host, Port, Opts, Node, "GET /pics/icon.sheet.gif " "HTTP/1.0\r\n\r\n", @@ -1043,9 +1042,10 @@ check_lists_members1(L1,L2) -> %% tsp(F) -> -%% tsp(F, []). -%% tsp(F, A) -> -%% test_server:format("~p ~p:" ++ F ++ "~n", [self(), ?MODULE | A]). +%% inets_test_lib:tsp(F). +tsp(F, A) -> + inets_test_lib:tsp(F, A). + tsf(Reason) -> test_server:fail(Reason). diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl index 434fa17307..b03127691d 100644 --- a/lib/inets/test/inets_test_lib.erl +++ b/lib/inets/test/inets_test_lib.erl @@ -306,20 +306,49 @@ copy_files(FromDir, ToDir) -> copy_dirs(FromDirRoot, ToDirRoot) -> - {ok, Files} = file:list_dir(FromDirRoot), - lists:foreach( - fun(FileOrDir) -> - %% Check if it's a directory or a file - case filelib:is_dir(filename:join(FromDirRoot, FileOrDir)) of - true -> - FromDir = filename:join([FromDirRoot, FileOrDir]), - ToDir = filename:join([ToDirRoot, FileOrDir]), - ok = file:make_dir(ToDir), - copy_dirs(FromDir, ToDir); - false -> - copy_file(FileOrDir, FromDirRoot, ToDirRoot) - end - end, Files). + case file:list_dir(FromDirRoot) of + {ok, Files} -> + lists:foreach( + fun(FileOrDir) -> + %% Check if it's a directory or a file + case filelib:is_dir(filename:join(FromDirRoot, + FileOrDir)) of + true -> + FromDir = filename:join([FromDirRoot, FileOrDir]), + ToDir = filename:join([ToDirRoot, FileOrDir]), + case file:make_dir(ToDir) of + ok -> + copy_dirs(FromDir, ToDir); + {error, Reason} -> + tsp(" Failed creating directory: " + "~n ToDir: ~p" + "~n Reason: ~p" + "~nwhen" + "~n ToDirRoot: ~p" + "~n ToDirRoot file info: ~p", + [ToDir, + Reason, + ToDirRoot, + file:read_file_info(ToDirRoot)]), + tsf({failed_copy_dir, ToDir, Reason}) + end; + false -> + copy_file(FileOrDir, FromDirRoot, ToDirRoot) + end + end, Files); + {error, Reason} -> + tsp(" Failed get directory file list: " + "~n FromDirRoot: ~p" + "~n Reason: ~p" + "~nwhen" + "~n FromDirRoot file info: ~p", + [FromDirRoot, + Reason, + file:read_file_info(FromDirRoot)]), + tsf({failed_list_dir, FromDirRoot, Reason}) + end. + + del_dirs(Dir) -> case file:list_dir(Dir) of -- cgit v1.2.3 From 4d849824fccb58764f6733c4d30a74906dd92b00 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 6 Feb 2012 17:46:21 +0100 Subject: [inets] Proper appup OTP-9805 --- lib/inets/src/inets_app/inets.appup.src | 52 ++++++++++++++------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index e80cb2a23b..9d7b1e6c93 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -18,8 +18,19 @@ {"%VSN%", [ + {"5.8.1", + [ + {load_module, httpd_conf, soft_purge, soft_purge, []}, + {load_module, httpd_response, soft_purge, soft_purge, []}, + {load_module, httpd_script_env, soft_purge, soft_purge, []} + ] + }, {"5.8", [ + {load_module, httpd_conf, soft_purge, soft_purge, []}, + {load_module, httpd_response, soft_purge, soft_purge, []}, + {load_module, httpd_script_env, soft_purge, soft_purge, []}, + {load_module, ftp, soft_purge, soft_purge, []}, {update, httpc_handler, {advanced, upgrade_from_pre_5_8_1}, soft_purge, soft_purge, []}, @@ -31,26 +42,22 @@ [ {restart_application, inets} ] - }, - {"5.7.1", - [ - {restart_application, inets} - ] - }, - {"5.7", - [ - {restart_application, inets} - ] - }, - {"5.6", - [ - {restart_application, inets} - ] } ], [ + {"5.8.1", + [ + {load_module, httpd_conf, soft_purge, soft_purge, []}, + {load_module, httpd_response, soft_purge, soft_purge, []}, + {load_module, httpd_script_env, soft_purge, soft_purge, []} + ] + }, {"5.8", [ + {load_module, httpd_conf, soft_purge, soft_purge, []}, + {load_module, httpd_response, soft_purge, soft_purge, []}, + {load_module, httpd_script_env, soft_purge, soft_purge, []}, + {load_module, ftp, soft_purge, soft_purge, []}, {update, httpc_handler, {advanced, upgrade_from_pre_5_8_1}, soft_purge, soft_purge, []}, @@ -62,21 +69,6 @@ [ {restart_application, inets} ] - }, - {"5.7.1", - [ - {restart_application, inets} - ] - }, - {"5.7", - [ - {restart_application, inets} - ] - }, - {"5.6", - [ - {restart_application, inets} - ] } ] }. -- cgit v1.2.3 From 6673b675b93de3e5466b18c7c8cd848b9dc6ec0a Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 8 Feb 2012 12:47:12 +0100 Subject: [inets/httpc] Connect error info improvement --- lib/inets/src/http_client/httpc_handler.erl | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl index 714fd6f16d..b8c34bd99b 100644 --- a/lib/inets/src/http_client/httpc_handler.erl +++ b/lib/inets/src/http_client/httpc_handler.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2011. All Rights Reserved. +%% Copyright Ericsson AB 2002-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -851,14 +851,16 @@ connect(SocketType, ToAddress, case IpFamily of inet6fb4 -> Opts3 = [inet6 | Opts2], - case http_transport:connect(SocketType, ToAddress, Opts3, Timeout) of + case http_transport:connect(SocketType, + ToAddress, Opts3, Timeout) of {error, Reason6} -> Opts4 = [inet | Opts2], case http_transport:connect(SocketType, ToAddress, Opts4, Timeout) of {error, Reason4} -> {error, {failed_connect, - [{inet6, Opts3, Reason6}, + [{to_address, ToAddress}, + {inet6, Opts3, Reason6}, {inet, Opts4, Reason4}]}}; OK -> OK @@ -870,7 +872,8 @@ connect(SocketType, ToAddress, Opts3 = [IpFamily | Opts2], case http_transport:connect(SocketType, ToAddress, Opts3, Timeout) of {error, Reason} -> - {error, {failed_connect, [{IpFamily, Opts3, Reason}]}}; + {error, {failed_connect, [{to_address, ToAddress}, + {IpFamily, Opts3, Reason}]}}; Else -> Else end -- cgit v1.2.3 From 9a8b3a5c58a2f688aaae1135bf71c6148f27aa7e Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 8 Feb 2012 12:50:21 +0100 Subject: [inets/httpd] Options parsing minor improvement --- lib/inets/src/http_server/httpd_conf.erl | 4 ++-- lib/inets/src/http_server/httpd_sup.erl | 19 ++++++++++++++++--- lib/inets/src/inets_app/inets.appup.src | 4 ++++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl index 2ffd134d3d..b575d7331b 100644 --- a/lib/inets/src/http_server/httpd_conf.erl +++ b/lib/inets/src/http_server/httpd_conf.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -495,7 +495,7 @@ validate_properties(Properties) -> validate_properties2(Properties) -> case proplists:get_value(bind_address, Properties) of undefined -> - case proplists:get_value(sock_type, Properties, ip_comm) of + case proplists:get_value(sock_type, Properties, ip_comm) of ip_comm -> case proplists:get_value(ipfamily, Properties) of undefined -> diff --git a/lib/inets/src/http_server/httpd_sup.erl b/lib/inets/src/http_server/httpd_sup.erl index 264dc9f006..8f3e8f9500 100644 --- a/lib/inets/src/http_server/httpd_sup.erl +++ b/lib/inets/src/http_server/httpd_sup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -162,17 +162,30 @@ httpd_config([Value| _] = Config) when is_tuple(Value) -> httpd_child_spec([Value| _] = Config, AcceptTimeout, Debug) when is_tuple(Value) -> + ?hdrt("httpd_child_spec - entry", [{accept_timeout, AcceptTimeout}, + {debug, Debug}]), Address = proplists:get_value(bind_address, Config, any), Port = proplists:get_value(port, Config, 80), httpd_child_spec(Config, AcceptTimeout, Debug, Address, Port); -httpd_child_spec(ConfigFile, AcceptTimeout, Debug) -> +%% In this case the AcceptTimeout and Debug will only have default values... +httpd_child_spec(ConfigFile, AcceptTimeoutDef, DebugDef) -> + ?hdrt("httpd_child_spec - entry", [{config_file, ConfigFile}, + {accept_timeout_def, AcceptTimeoutDef}, + {debug_def, DebugDef}]), case httpd_conf:load(ConfigFile) of {ok, ConfigList} -> + ?hdrt("httpd_child_spec - loaded", [{config_list, ConfigList}]), case (catch httpd_conf:validate_properties(ConfigList)) of {ok, Config} -> + ?hdrt("httpd_child_spec - validated", [{config, Config}]), Address = proplists:get_value(bind_address, Config, any), Port = proplists:get_value(port, Config, 80), + AcceptTimeout = + proplists:get_value(accept_timeout, Config, + AcceptTimeoutDef), + Debug = + proplists:get_value(debug, Config, DebugDef), httpd_child_spec([{file, ConfigFile} | Config], AcceptTimeout, Debug, Address, Port); Error -> @@ -183,7 +196,7 @@ httpd_child_spec(ConfigFile, AcceptTimeout, Debug) -> end. httpd_child_spec(Config, AcceptTimeout, Debug, Addr, Port) -> - case Port == 0 orelse proplists:is_defined(fd, Config) of + case (Port =:= 0) orelse proplists:is_defined(fd, Config) of true -> httpd_child_spec_listen(Config, AcceptTimeout, Debug, Addr, Port); false -> diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index 1be5a958ce..3bc7d69101 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -26,6 +26,7 @@ {load_module, inets, soft_purge, soft_purge, [inets_trace]}, {update, httpc_handler, soft, soft_purge, soft_purge, []}, + {update, httpd_sup, soft, soft_purge, soft_purge, []}, {add_module, inets_trace} ] }, @@ -42,6 +43,7 @@ soft_purge, soft_purge, []}, {update, httpc_manager, {advanced, upgrade_from_pre_5_8_1}, soft_purge, soft_purge, [httpc_handler]}, + {update, httpd_sup, soft, soft_purge, soft_purge, []}, {add_module, inets_trace} ] @@ -61,6 +63,7 @@ {load_module, inets, soft_purge, soft_purge, []}, {update, httpc_handler, soft, soft_purge, soft_purge, []}, + {update, httpd_sup, soft, soft_purge, soft_purge, []}, {remove, {inets_trace, soft_purge, brutal_purge}} ] }, @@ -77,6 +80,7 @@ soft_purge, soft_purge, []}, {update, httpc_manager, {advanced, upgrade_from_pre_5_8_1}, soft_purge, soft_purge, [httpc_handler]}, + {update, httpd_sup, soft, soft_purge, soft_purge, []}, {remove, {inets_trace, soft_purge, brutal_purge}} ] -- cgit v1.2.3 From 3f89830e526e4fb7556c8a9fb79859fbd85756ac Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 8 Feb 2012 12:52:26 +0100 Subject: [inets] Force use of IPv4 for all non-IPv6 cases --- lib/inets/test/httpc_SUITE.erl | 10 +++++-- lib/inets/test/httpd_SUITE.erl | 42 ++++++++++++++-------------- lib/inets/test/inets_test_lib.erl | 58 +++++++++++++++++++++++++++------------ 3 files changed, 68 insertions(+), 42 deletions(-) diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 734964698e..9bbd957473 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -375,6 +375,7 @@ init_per_testcase(Case, Timeout, Config) -> TmpConfig2 = lists:keydelete(local_server, 1, TmpConfig), %% Will start inets + tsp("init_per_testcase -> try start server"), Server = start_http_server(PrivDir, IpConfFile), [{watchdog, Dog}, {local_server, Server} | TmpConfig2] end, @@ -3298,7 +3299,10 @@ create_config(FileName, ComType, Port, PrivDir, ServerRoot, DocRoot, " mod_include mod_dir mod_get mod_head" " mod_log mod_disk_log mod_trace", + BindAddress = "*|inet", + HttpConfig = [ + cline(["BindAddress ", BindAddress]), cline(["Port ", integer_to_list(Port)]), cline(["ServerName ", "httpc_test"]), cline(["SocketType ", atom_to_list(ComType)]), @@ -3895,9 +3899,9 @@ p(F, A) -> io:format("~p ~w:" ++ F ++ "~n", [self(), ?MODULE | A]). tsp(F) -> - inets_test_lib:tsp(F). + inets_test_lib:tsp("[~w]" ++ F, [?MODULE]). tsp(F, A) -> - inets_test_lib:tsp(F, A). + inets_test_lib:tsp("[~w]" ++ F, [?MODULE|A]). tsf(Reason) -> test_server:fail(Reason). diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index 907d58fd8c..51ccff5720 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2011. All Rights Reserved. +%% Copyright Ericsson AB 2005-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -366,8 +366,8 @@ init_per_testcase(Case, Config) -> init_per_testcase2(Case, Config) -> - tsp("init_per_testcase2(~w) -> entry with" - "~n Config: ~p", [Case, Config]), + tsp("init_per_testcase2 -> entry with" + "~n Config: ~p", [Config]), IpNormal = integer_to_list(?IP_PORT) ++ ".conf", IpHtaccess = integer_to_list(?IP_PORT) ++ "htaccess.conf", @@ -377,33 +377,33 @@ init_per_testcase2(Case, Config) -> DataDir = ?config(data_dir, Config), SuiteTopDir = ?config(suite_top_dir, Config), - tsp("init_per_testcase2(~w) -> " + tsp("init_per_testcase2 -> " "~n SuiteDir: ~p" - "~n DataDir: ~p", [Case, SuiteTopDir, DataDir]), + "~n DataDir: ~p", [SuiteTopDir, DataDir]), TcTopDir = filename:join(SuiteTopDir, Case), ?line ok = file:make_dir(TcTopDir), - tsp("init_per_testcase2(~w) -> " - "~n TcTopDir: ~p", [Case, TcTopDir]), + tsp("init_per_testcase2 -> " + "~n TcTopDir: ~p", [TcTopDir]), DataSrc = filename:join([DataDir, "server_root"]), ServerRoot = filename:join([TcTopDir, "server_root"]), - tsp("init_per_testcase2(~w) -> " + tsp("init_per_testcase2 -> " "~n DataSrc: ~p" - "~n ServerRoot: ~p", [Case, DataSrc, ServerRoot]), + "~n ServerRoot: ~p", [DataSrc, ServerRoot]), ok = file:make_dir(ServerRoot), ok = file:make_dir(filename:join([TcTopDir, "logs"])), NewConfig = [{tc_top_dir, TcTopDir}, {server_root, ServerRoot} | Config], - tsp("init_per_testcase2(~w) -> copy DataSrc to ServerRoot", [Case]), + tsp("init_per_testcase2 -> copy DataSrc to ServerRoot"), inets_test_lib:copy_dirs(DataSrc, ServerRoot), - tsp("init_per_testcase2(~w) -> fix cgi", [Case]), + tsp("init_per_testcase2 -> fix cgi"), EnvCGI = filename:join([ServerRoot, "cgi-bin", "printenv.sh"]), {ok, FileInfo} = file:read_file_info(EnvCGI), ok = file:write_file_info(EnvCGI, @@ -423,14 +423,14 @@ init_per_testcase2(Case, Config) -> FileInfo1#file_info{mode = 8#00755}), %% To be used by IP test cases - tsp("init_per_testcase2(~w) -> ip testcase setups", [Case]), + tsp("init_per_testcase2 -> ip testcase setups"), create_config([{port, ?IP_PORT}, {sock_type, ip_comm} | NewConfig], normal_access, IpNormal), create_config([{port, ?IP_PORT}, {sock_type, ip_comm} | NewConfig], mod_htaccess, IpHtaccess), %% To be used by SSL test cases - tsp("init_per_testcase2(~w) -> ssl testcase setups", [Case]), + tsp("init_per_testcase2 -> ssl testcase setups"), SocketType = case atom_to_list(Case) of [X, $s, $s, $l | _] -> @@ -454,7 +454,7 @@ init_per_testcase2(Case, Config) -> %% when you run the whole test suite due to shortcomings %% of the test server. - tsp("init_per_testcase2(~w) -> maybe generate IPv6 config file(s)", [Case]), + tsp("init_per_testcase2 -> maybe generate IPv6 config file(s)"), NewConfig2 = case atom_to_list(Case) of "ipv6_" ++ _ -> @@ -495,8 +495,8 @@ init_per_testcase2(Case, Config) -> NewConfig end, - tsp("init_per_testcase2(~w) -> done when" - "~n NewConfig2: ~p", [Case, NewConfig2]), + tsp("init_per_testcase2 -> done when" + "~n NewConfig2: ~p", [NewConfig2]), NewConfig2. @@ -2372,8 +2372,8 @@ create_config(Config, Access, FileName) -> %% AddrStr = make_ipv6(Addr), %% BindAddress = lists:flatten(io_lib:format("~s|inet6", [AddrStr])), - %% BindAddress = "*|inet", - BindAddress = "*", + BindAddress = "*|inet", + %% BindAddress = "*", HttpConfig = [ cline(["Port ", integer_to_list(Port)]), @@ -2764,10 +2764,10 @@ create_ipv6_config(Config, FileName, Ipv6Address) -> ok = file:close(Fd). -%% tsp(F) -> -%% inets_test_lib:tsp(F). +tsp(F) -> + inets_test_lib:tsp("[~w]" ++ F, [?MODULE]). tsp(F, A) -> - inets_test_lib:tsp(F, A). + inets_test_lib:tsp("[~w]" ++ F, [?MODULE|A]). tsf(Reason) -> inets_test_lib:tsf(Reason). diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl index b03127691d..0c21d6661c 100644 --- a/lib/inets/test/inets_test_lib.erl +++ b/lib/inets/test/inets_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2011. All Rights Reserved. +%% Copyright Ericsson AB 2001-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -205,6 +205,17 @@ do_ensure_started(App, Start) when is_function(Start) -> end. +ensure_loaded(App) -> + case application:load(App) of + ok -> + ok; + {error, {already_loaded,inets}} -> + ok; + Error -> + Error + end. + + %% ---------------------------------------------------------------- %% HTTPD starter functions @@ -214,8 +225,9 @@ start_http_server(Conf) -> start_http_server(Conf, ?HTTP_DEFAULT_SSL_KIND). start_http_server(Conf, essl = _SslTag) -> - tsp("start_http_server(essl) -> entry - try start crypto and public_key"), + tsp("start_http_server(essl) -> try start crypto"), application:start(crypto), + tsp("start_http_server(essl) -> try start public_key"), application:start(public_key), do_start_http_server(Conf); start_http_server(Conf, SslTag) -> @@ -226,23 +238,32 @@ do_start_http_server(Conf) -> tsp("do_start_http_server -> entry with" "~n Conf: ~p" "~n", [Conf]), - application:load(inets), - case application:set_env(inets, services, [{httpd, Conf}]) of + tsp("do_start_http_server -> load inets"), + case ensure_loaded(inets) of ok -> - tsp("start_http_server -> httpd conf stored in inets app env"), - case application:start(inets) of + tsp("do_start_http_server -> inets loaded - now set_env for httpd"), + case application:set_env(inets, services, [{httpd, Conf}]) of ok -> - tsp("start_http_server -> inets started"), - ok; - Error1 -> - tsp(" Failed starting application: " - "~n Error1: ~p", [Error1]), - Error1 + tsp("do_start_http_server -> " + "httpd conf stored in inets app env"), + case (catch application:start(inets)) of + ok -> + tsp("do_start_http_server -> inets started"), + ok; + Error1 -> + tsp(" Failed starting application: " + "~n Error1: ~p", [Error1]), + tsf({failed_starting_inets, Error1}) + end; + Error2 -> + tsp(" Failed set application env: " + "~n Error: ~p", [Error2]), + tsf({failed_set_env, Error2}) end; - Error2 -> - tsp(" Failed set application env: " - "~n Error: ~p", [Error2]), - Error2 + {error, Reason} -> + tsp("do_start_http_server -> failed loading inets" + "~n Reason: ~p", [Reason]), + tsf({failed_loading_inets, Reason}) end. start_http_server_ssl(FileName) -> @@ -262,6 +283,7 @@ do_start_http_server_ssl(FileName) -> catch do_start_http_server(FileName). + %% ---------------------------------------------------------------------- %% print functions %% @@ -615,8 +637,8 @@ tsp(F) -> tsp(F, []). tsp(F, A) -> Timestamp = formated_timestamp(), - test_server:format("*** ~s ~p ~p ~w:" ++ F ++ "~n", - [Timestamp, node(), self(), ?MODULE | A]). + test_server:format("*** ~s ~p ~p " ++ F ++ "~n", + [Timestamp, node(), self() | A]). tsf(Reason) -> test_server:fail(Reason). -- cgit v1.2.3 From 1b257c80e9b1097ac762840cada2c607f1126bda Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 9 Feb 2012 12:01:00 +0100 Subject: [inets] Used invalid transport option for ssl (inet6fb4) --- lib/inets/test/httpd_mod.erl | 9 +-------- lib/inets/test/inets_test_lib.erl | 5 +++-- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/lib/inets/test/httpd_mod.erl b/lib/inets/test/httpd_mod.erl index 25a03ab9c8..23551ab125 100644 --- a/lib/inets/test/httpd_mod.erl +++ b/lib/inets/test/httpd_mod.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2011. All Rights Reserved. +%% Copyright Ericsson AB 2005-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -39,13 +39,6 @@ %% Test cases starts here. %%------------------------------------------------------------------------- alias(Type, Port, Host, Node) -> - %% io:format(user, "~w:alias -> entry with" -%% "~n Type: ~p" -%% "~n Port: ~p" -%% "~n Host: ~p" -%% "~n Node: ~p" -%% "~n", [?MODULE, Type, Port, Host, Node]), - %% This is very crude, but... tsp("alias -> Has IPv6 support: ~p", [inets_test_lib:has_ipv6_support()]), Opts = case os:type() of diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl index 0c21d6661c..6129607f69 100644 --- a/lib/inets/test/inets_test_lib.erl +++ b/lib/inets/test/inets_test_lib.erl @@ -500,8 +500,9 @@ connect(ssl, Host, Port, Opts) -> "~n Port: ~p" "~n Opts: ~p", [Host, Port, Opts]), ssl:start(), - %% Does not support ipv6 in old ssl - case ssl:connect(Host, Port, Opts) of + %% We ignore this option for ssl... + %% ...maybe we should really treat this in the same way as ip_comm... + case ssl:connect(Host, Port, lists:delete(inet6fb4, Opts)) of {ok, Socket} -> {ok, Socket}; {error, Reason} -> -- cgit v1.2.3 From ff09910333c1589bf75e44fb33ad16e3cbff5000 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 9 Feb 2012 12:47:01 +0100 Subject: [inets] Minor improvement to escaped_url_in_error_body --- lib/inets/test/httpd_basic_SUITE.erl | 14 ++++++++++++-- lib/inets/test/inets_test_lib.erl | 5 ++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl index be0bcc67d5..c75c8c57a4 100644 --- a/lib/inets/test/httpd_basic_SUITE.erl +++ b/lib/inets/test/httpd_basic_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -192,6 +192,7 @@ escaped_url_in_error_body(Config) when is_list(Config) -> _Address = proplists:get_value(bind_address, Info), %% Request 1 + tss(1000), tsp("escaped_url_in_error_body -> request 1"), URL1 = ?URL_START ++ integer_to_list(Port), %% Make sure the server is ok, by making a request for a valid page @@ -207,6 +208,7 @@ escaped_url_in_error_body(Config) when is_list(Config) -> end, %% Request 2 + tss(1000), tsp("escaped_url_in_error_body -> request 2"), %% Make sure the server is ok, by making a request for a valid page case httpc:request(get, {URL1 ++ "/dummy.html", []}, @@ -221,6 +223,7 @@ escaped_url_in_error_body(Config) when is_list(Config) -> end, %% Request 3 + tss(1000), tsp("escaped_url_in_error_body -> request 3"), %% Ask for a non-existing page(1) Path = "/this_is_bold", @@ -242,6 +245,7 @@ escaped_url_in_error_body(Config) when is_list(Config) -> end, %% Request 4 + tss(1000), tsp("escaped_url_in_error_body -> request 4"), %% Ask for a non-existing page(2) case httpc:request(get, {URL2, []}, @@ -258,6 +262,7 @@ escaped_url_in_error_body(Config) when is_list(Config) -> {ok, UnexpectedOK4} -> tsf({unexpected_ok_4, UnexpectedOK4}) end, + tss(1000), tsp("escaped_url_in_error_body -> stop inets"), inets:stop(httpd, Pid), tsp("escaped_url_in_error_body -> done"), @@ -277,7 +282,12 @@ tsp(F, A) -> inets_test_lib:tsp(F, A). tsf(Reason) -> - test_server:fail(Reason). + inets_test_lib:tsf(Reason). + +tss(Time) -> + inets_test_lib:tss(Time). + + skip(Reason) -> diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl index 6129607f69..a4815becba 100644 --- a/lib/inets/test/inets_test_lib.erl +++ b/lib/inets/test/inets_test_lib.erl @@ -31,7 +31,7 @@ send/3, close/2]). -export([copy_file/3, copy_files/2, copy_dirs/2, del_dirs/1]). -export([info/4, log/4, debug/4, print/4]). --export([tsp/1, tsp/2, tsf/1]). +-export([tsp/1, tsp/2, tsf/1, tss/1]). -export([check_body/1]). -export([millis/0, millis_diff/2, hours/1, minutes/1, seconds/1, sleep/1]). -export([oscmd/1, has_ipv6_support/0, has_ipv6_support/1, print_system_info/1]). @@ -644,6 +644,9 @@ tsp(F, A) -> tsf(Reason) -> test_server:fail(Reason). +tss(Time) -> + test_server:sleep(Time). + formated_timestamp() -> format_timestamp( os:timestamp() ). -- cgit v1.2.3 From 1ef8d7ee1e971e20c6c18363b3745101b4ce5f92 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 9 Feb 2012 16:23:55 +0100 Subject: [inets] Add test case group check for IPv6 support --- lib/inets/test/httpc_SUITE.erl | 105 ++++++++++++++++++++++++----------------- lib/inets/test/httpd_SUITE.erl | 11 ++++- 2 files changed, 71 insertions(+), 45 deletions(-) diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 9bbd957473..3484a36047 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -146,6 +146,20 @@ groups() -> ]. +init_per_group(ipv6 = _GroupName, Config) -> + case inets_test_lib:has_ipv6_support() of + {ok, _} -> + Config; + _ -> + {skip, "Host does not support IPv6"} + end; +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + %%-------------------------------------------------------------------- %% Function: init_per_suite(Config) -> Config %% Config - [tuple()] @@ -234,12 +248,12 @@ init_per_testcase(initial_server_connect = Case, Config) -> "~n ~p", [Case, App, ActualError]), SkipString = "Could not start " ++ atom_to_list(App), - {skip, SkipString}; + skip(SkipString); _:X -> SkipString = lists:flatten( io_lib:format("Failed starting apps: ~p", [X])), - {skip, SkipString} + skip(SkipString) end; init_per_testcase(Case, Config) -> @@ -352,12 +366,12 @@ init_per_testcase(Case, Timeout, Config) -> "~n ~p", [Case, App, ActualError]), SkipString = "Could not start " ++ atom_to_list(App), - {skip, SkipString}; + skip(SkipString); _:X -> SkipString = lists:flatten( io_lib:format("Failed starting apps: ~p", [X])), - {skip, SkipString} + skip(SkipString) end; _ -> @@ -471,7 +485,7 @@ http_options(doc) -> http_options(suite) -> []; http_options(Config) when is_list(Config) -> - {skip, "Not supported by httpd"}. + skip("Not supported by httpd"). http_head(doc) -> ["Test http head request against local server."]; @@ -549,7 +563,7 @@ http_get(Config) when is_list(Config) -> tsf({bad_reply, Error2}) end; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. %%------------------------------------------------------------------------- @@ -585,7 +599,7 @@ http_post(Config) when is_list(Config) -> httpc:request(post, {URL, [{"expect","100-continue"}], "text/plain", "foobar"}, [], []); _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. %%------------------------------------------------------------------------- @@ -631,7 +645,7 @@ http_post_streaming(Config) when is_list(Config) -> "text/plain", {BodyFun, 10}}, [], []); _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. @@ -655,7 +669,7 @@ http_emulate_lower_versions(Config) when is_list(Config) -> httpc:request(get, {URL, []}, [{version, "HTTP/1.1"}], []), inets_test_lib:check_body(Body2); _-> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. @@ -716,7 +730,7 @@ http_inets_pipe(Config) when is_list(Config) -> URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", test_pipeline(URL); _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. @@ -852,7 +866,7 @@ http_trace(Config) when is_list(Config) -> tsf({failed, Error}) end; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. %%------------------------------------------------------------------------- http_async(doc) -> @@ -887,7 +901,7 @@ http_async(Config) when is_list(Config) -> ok end; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. %%------------------------------------------------------------------------- @@ -908,7 +922,7 @@ http_save_to_file(Config) when is_list(Config) -> {ok, {{_,200,_}, [_ | _], Body}} = httpc:request(URL), Bin == Body; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. @@ -938,7 +952,7 @@ http_save_to_file_async(Config) when is_list(Config) -> {ok, {{_,200,_}, [_ | _], Body}} = httpc:request(URL), Bin == Body; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. %%------------------------------------------------------------------------- http_headers(doc) -> @@ -995,7 +1009,7 @@ http_headers(Config) when is_list(Config) -> ]}, [], []), ok; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. %%------------------------------------------------------------------------- @@ -1130,9 +1144,9 @@ ssl_head(SslTag, Config) -> {ok, {{_,200, _}, [_ | _], []}} = httpc:request(head, {URL, []}, [{ssl, SSLConfig}], []); {ok, _} -> - {skip, "local http-server not started"}; + skip("local http-server not started"); _ -> - {skip, "SSL not started"} + skip("SSL not started") end. @@ -1185,9 +1199,9 @@ ssl_get(SslTag, Config) when is_list(Config) -> tsf({request_failed, Reason}) end; {ok, _} -> - {skip, "local http-server not started"}; + skip("local http-server not started"); _ -> - {skip, "SSL not started"} + skip("SSL not started") end. @@ -1236,9 +1250,9 @@ ssl_trace(SslTag, Config) when is_list(Config) -> tsf({failed, Error}) end; {ok, _} -> - {skip, "local http-server not started"}; + skip("local http-server not started"); _ -> - {skip, "SSL not started"} + skip("SSL not started") end. @@ -1357,7 +1371,7 @@ http_redirect(Config) when is_list(Config) -> ok; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. @@ -1494,7 +1508,7 @@ proxy_options(Config) when is_list(Config) -> tsf({unexpected_result, Unexpected}) end; Reason -> - {skip, Reason} + skip(Reason) end. @@ -1515,7 +1529,7 @@ proxy_head(Config) when is_list(Config) -> tsf({unexpected_result, Unexpected}) end; Reason -> - {skip, Reason} + skip(Reason) end. @@ -1534,7 +1548,7 @@ proxy_get(Config) when is_list(Config) -> tsf({unexpected_result, Unexpected}) end; Reason -> - {skip, Reason} + skip(Reason) end. %%------------------------------------------------------------------------- @@ -1575,12 +1589,13 @@ proxy_emulate_lower_versions(Config) when is_list(Config) -> end; Reason -> - {skip, Reason} + skip(Reason) end. pelv_get(Version) -> httpc:request(get, {?PROXY_URL, []}, [{version, Version}], []). + %%------------------------------------------------------------------------- proxy_trace(doc) -> ["Perform a TRACE request that goes through a proxy."]; @@ -1589,8 +1604,8 @@ proxy_trace(suite) -> proxy_trace(Config) when is_list(Config) -> %%{ok, {{_,200,_}, [_ | _], "TRACE " ++ _}} = %% httpc:request(trace, {?PROXY_URL, []}, [], []), - {skip, "HTTP TRACE is no longer allowed on the ?PROXY_URL server due " - "to security reasons"}. + skip("HTTP TRACE is no longer allowed on the ?PROXY_URL server due " + "to security reasons"). %%------------------------------------------------------------------------- @@ -1613,7 +1628,7 @@ proxy_post(Config) when is_list(Config) -> tsf({unexpected_result, Unexpected}) end; Reason -> - {skip, Reason} + skip(Reason) end. @@ -1638,7 +1653,7 @@ proxy_put(Config) when is_list(Config) -> tsf({unexpected_result, Unexpected}) end; Reason -> - {skip, Reason} + skip(Reason) end. @@ -1663,7 +1678,7 @@ proxy_delete(Config) when is_list(Config) -> tsf({unexpected_result, Unexpected}) end; Reason -> - {skip, Reason} + skip(Reason) end. @@ -1697,9 +1712,10 @@ proxy_headers(Config) when is_list(Config) -> ]}, [], []), ok; Reason -> - {skip, Reason} + skip(Reason) end. + %%------------------------------------------------------------------------- proxy_auth(doc) -> ["Test the code for sending of proxy authorization."]; @@ -1719,7 +1735,7 @@ proxy_auth(Config) when is_list(Config) -> tsf({unexpected_result, Unexpected}) end; Reason -> - {skip, Reason} + skip(Reason) end. @@ -1763,7 +1779,7 @@ proxy_page_does_not_exist(Config) when is_list(Config) -> httpc:request(get, {URL, []}, [], []), ok; Reason -> - {skip, Reason} + skip(Reason) end. @@ -1782,6 +1798,7 @@ proxy_https_not_supported(Config) when is_list(Config) -> tsf({unexpected_reason, Result}) end. + %%------------------------------------------------------------------------- http_stream(doc) -> @@ -1908,7 +1925,7 @@ proxy_stream(Config) when is_list(Config) -> Body == binary_to_list(StreamedBody); Reason -> - {skip, Reason} + skip(Reason) end. @@ -2011,7 +2028,7 @@ ipv6_essl(Config) when is_list(Config) -> ipv6(SocketType, Scheme, HTTPOptions, Extra, Config) -> %% Check if we are a IPv6 host - tsp("ipv6 -> verify ipv6 support", []), + tsp("ipv6 -> verify ipv6 support"), case inets_test_lib:has_ipv6_support(Config) of {ok, Addr} -> tsp("ipv6 -> ipv6 supported: ~p", [Addr]), @@ -2042,8 +2059,8 @@ ipv6(SocketType, Scheme, HTTPOptions, Extra, Config) -> end, ok; _ -> - tsp("ipv6 -> ipv6 not supported", []), - {skip, "Host does not support IPv6"} + tsp("ipv6 -> ipv6 not supported"), + skip("Host does not support IPv6") end. @@ -2400,7 +2417,7 @@ options(Config) when is_list(Config) -> = httpc:request(get, {URL, []}, [{timeout, infinity}], [{full_result, false}]); _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. @@ -2513,7 +2530,7 @@ proxy_not_modified_otp_6821(Config) when is_list(Config) -> undefined -> provocate_not_modified_bug(?PROXY_URL); Reason -> - {skip, Reason} + skip(Reason) end. @@ -2915,7 +2932,7 @@ otp_8106_pid(Config) when is_list(Config) -> ok; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. @@ -2935,7 +2952,7 @@ otp_8106_fun(Config) when is_list(Config) -> ok; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. @@ -2955,7 +2972,7 @@ otp_8106_mfa(Config) when is_list(Config) -> ok; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. @@ -3104,7 +3121,7 @@ otp_8352(Config) when is_list(Config) -> ok; _ -> - {skip, "Failed to start local http-server"} + skip("Failed to start local http-server") end. diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index 51ccff5720..07c529acc8 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -224,7 +224,8 @@ all() -> ]. groups() -> - [{ip, [], + [ + {ip, [], [ip_mod_alias, ip_mod_actions, ip_mod_security, ip_mod_auth, ip_mod_auth_api, ip_mod_auth_mnesia_api, ip_mod_htaccess, ip_mod_cgi, ip_mod_esi, ip_mod_get, @@ -293,6 +294,14 @@ groups() -> [ticket_5775, ticket_5865, ticket_5913, ticket_6003, ticket_7304]}]. + +init_per_group(ipv6 = _GroupName, Config) -> + case inets_test_lib:has_ipv6_support() of + {ok, _} -> + Config; + _ -> + {skip, "Host does not support IPv6"} + end; init_per_group(_GroupName, Config) -> Config. -- cgit v1.2.3 From fae2034ba30fd9936960418ba36b90ca7028bb3d Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 10 Feb 2012 15:12:11 +0100 Subject: [inets] Skip test case on windows (long path's) On windows we have a problem opening files when the path's are long (error reason eio). --- lib/inets/test/httpd_basic_SUITE.erl | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl index c75c8c57a4..7a476ea14a 100644 --- a/lib/inets/test/httpd_basic_SUITE.erl +++ b/lib/inets/test/httpd_basic_SUITE.erl @@ -20,6 +20,8 @@ -module(httpd_basic_SUITE). -include_lib("common_test/include/ct.hrl"). +-include("inets_test_lib.hrl"). + %% Note: This directive should only be used in test suites. -compile(export_all). @@ -184,6 +186,15 @@ escaped_url_in_error_body(doc) -> escaped_url_in_error_body(suite) -> []; escaped_url_in_error_body(Config) when is_list(Config) -> + %% + %% This skip is due to a problem on windows with long path's + %% If a path is too long file:open fails with, for example, eio. + %% Until that problem is fixed, we skip this case... + Skippable = [win32], + Condition = fun() -> ?OS_BASED_SKIP(Skippable) end, + ?NON_PC_TC_MAYBE_SKIP(Config, Condition), + %% + tsp("escaped_url_in_error_body -> entry"), HttpdConf = ?config(httpd_conf, Config), {ok, Pid} = inets:start(httpd, [{port, 0} | HttpdConf]), -- cgit v1.2.3 From 66288284701787c7b9e1775ec9bc91732c87f51d Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 29 Feb 2012 15:19:54 +0100 Subject: [inets/httpc] Make inets tests behave on all IPv6 impl Updated according to pan/inets_ipv6_test_issues as far as possible (that branch is based on master). --- lib/inets/test/httpc_SUITE.erl | 44 ++++++++++----- lib/inets/test/httpd_SUITE.erl | 41 +++++++------- lib/inets/test/inets_test_lib.erl | 115 ++++++++++++++++++-------------------- 3 files changed, 107 insertions(+), 93 deletions(-) diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 3484a36047..a18d079426 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -275,6 +275,20 @@ init_per_testcase(Case, Timeout, Config) -> %% inets:enable_trace(max, io, httpc), %% inets:enable_trace(max, io, all), + %% + % Set default ipfamily to the same as the main server has by default + %% This makes the client try w/ ipv6 before falling back to ipv4, + %% as that is what the server is configured to do. + %% Note that this is required for the tests to run on *BSD w/ ipv6 enabled + %% as well as on Windows. The Linux behaviour of allowing ipv4 connects + %% to ipv6 sockets is not required or even encouraged. + + httpc:set_options([{ipfamily, inet6fb4}]), + + %% Note that the IPv6 trest case *must* use inet6, + %% so this value will be overwritten (see "ipv6_" below). + %% + NewConfig = case atom_to_list(Case) of [$s, $s, $l | _] -> @@ -376,16 +390,18 @@ init_per_testcase(Case, Timeout, Config) -> _ -> %% Try inet6fb4 on windows... - tsp("init_per_testcase -> allways try IPv6 on windows"), - ?RUN_ON_WINDOWS( - fun() -> - tsp("init_per_testcase:set_options_fun -> " - "set-option ipfamily to inet6fb4"), - Res = httpc:set_options([{ipfamily, inet6fb4}]), - tsp("init_per_testcase:set_options_fun -> " - "~n Res: ~p", [Res]), - Res - end), + %% No need? Since it is set above? + + %% tsp("init_per_testcase -> allways try IPv6 on windows"), + %% ?RUN_ON_WINDOWS( + %% fun() -> + %% tsp("init_per_testcase:set_options_fun -> " + %% "set-option ipfamily to inet6fb4"), + %% Res = httpc:set_options([{ipfamily, inet6fb4}]), + %% tsp("init_per_testcase:set_options_fun -> " + %% "~n Res: ~p", [Res]), + %% Res + %% end), TmpConfig2 = lists:keydelete(local_server, 1, TmpConfig), %% Will start inets @@ -441,6 +457,7 @@ end_per_testcase(http_save_to_file = Case, Config) -> end_per_testcase(Case, Config) -> io:format(user, "~n~n*** END ~w:~w ***~n~n", [?MODULE, Case]), + dbg:stop(), % ? case atom_to_list(Case) of "ipv6_" ++ _Rest -> tsp("end_per_testcase(~w) -> stop ssl", [Case]), @@ -1267,8 +1284,8 @@ http_redirect(Config) when is_list(Config) -> "~n Config: ~p", [Config]), case ?config(local_server, Config) of ok -> - tsp("http_redirect -> set ipfamily option to inet"), - ok = httpc:set_options([{ipfamily, inet}]), + %% tsp("http_redirect -> set ipfamily option to inet"), + %% ok = httpc:set_options([{ipfamily, inet}]), tsp("http_redirect -> start dummy server inet"), {DummyServerPid, Port} = dummy_server(ipv4), @@ -3316,7 +3333,8 @@ create_config(FileName, ComType, Port, PrivDir, ServerRoot, DocRoot, " mod_include mod_dir mod_get mod_head" " mod_log mod_disk_log mod_trace", - BindAddress = "*|inet", + %% BindAddress = "*|inet", % Force the use of IPv4 + BindAddress = "*", % This corresponds to using IpFamily inet6fb4 HttpConfig = [ cline(["BindAddress ", BindAddress]), diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index 07c529acc8..41e4188e5f 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -2357,29 +2357,30 @@ create_config(Config, Access, FileName) -> true -> [] end, - ModOrder = case Access of - mod_htaccess -> - "Modules mod_alias mod_htaccess mod_auth " - "mod_security " - "mod_responsecontrol mod_trace mod_esi " - "mod_actions mod_cgi mod_include mod_dir " - "mod_range mod_get " - "mod_head mod_log mod_disk_log"; - _ -> - "Modules mod_alias mod_auth mod_security " - "mod_responsecontrol mod_trace mod_esi " - "mod_actions mod_cgi mod_include mod_dir " + ModOrder = + case Access of + mod_htaccess -> + "Modules mod_alias mod_htaccess mod_auth " + "mod_security " + "mod_responsecontrol mod_trace mod_esi " + "mod_actions mod_cgi mod_include mod_dir " + "mod_range mod_get " + "mod_head mod_log mod_disk_log"; + _ -> + "Modules mod_alias mod_auth mod_security " + "mod_responsecontrol mod_trace mod_esi " + "mod_actions mod_cgi mod_include mod_dir " "mod_range mod_get " - "mod_head mod_log mod_disk_log" - end, + "mod_head mod_log mod_disk_log" + end, -%% The test suite currently does not handle an explicit BindAddress. -%% They assume any has been used, that is Addr is always set to undefined! + %% The test suite currently does not handle an explicit BindAddress. + %% They assume any has been used, that is Addr is always set to undefined! -%% {ok, Hostname} = inet:gethostname(), -%% {ok, Addr} = inet:getaddr(Hostname, inet6), -%% AddrStr = make_ipv6(Addr), -%% BindAddress = lists:flatten(io_lib:format("~s|inet6", [AddrStr])), + %% {ok, Hostname} = inet:gethostname(), + %% {ok, Addr} = inet:getaddr(Hostname, inet6), + %% AddrStr = make_ipv6(Addr), + %% BindAddress = lists:flatten(io_lib:format("~s|inet6", [AddrStr])), BindAddress = "*|inet", %% BindAddress = "*", diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl index a4815becba..c94be796cd 100644 --- a/lib/inets/test/inets_test_lib.erl +++ b/lib/inets/test/inets_test_lib.erl @@ -494,83 +494,78 @@ connect_byte(ip_comm, Host, Port, Opts0) -> connect(ip_comm, Host, Port, Opts). -connect(ssl, Host, Port, Opts) -> +%% This always falls back on IPV4, but tries IPV6 first. +connect(Proto, Host, Port, Opts0) -> + Opts = Opts0 -- [inet, inet6], + connect(Proto, Host, Port, Opts ++ [inet6], inet6). + +connect(ssl, Host, Port, Opts, Type) -> tsp("connect(ssl) -> entry with" "~n Host: ~p" "~n Port: ~p" - "~n Opts: ~p", [Host, Port, Opts]), + "~n Opts: ~p" + "~n Type: ~p", [Host, Port, Opts, Type]), ssl:start(), %% We ignore this option for ssl... %% ...maybe we should really treat this in the same way as ip_comm... - case ssl:connect(Host, Port, lists:delete(inet6fb4, Opts)) of + case ssl:connect(Host, Port, Opts) of {ok, Socket} -> {ok, Socket}; + {error, Reason} when Type =:= inet6 -> + tsp("connect(ssl) -> failed connecting with inet6: " + "~n Reason: ~p" + "~n trying inet", [Reason]), + connect(ssl, Host, Port, Opts -- [inet6], inet); {error, Reason} -> - {error, Reason}; + tsp("connect(ssl) -> failed connecting: " + "~n Reason: ~p", [Reason]), + {error, Reason}; Error -> Error end; -connect(ip_comm, Host, Port, Opts) -> +connect(ip_comm, Host, Port, Opts, Type) -> tsp("connect(ip_comm) -> entry with" "~n Host: ~p" "~n Port: ~p" - "~n Opts: ~p", [Host, Port, Opts]), + "~n Opts: ~p" + "~n Type: ~p", [Host, Port, Opts, Type]), - %% We check for precence of inet6fb4. - %% If found, we shall try inet6 and if that does not work - %% try inet (regardless of error reason) - case lists:delete(inet6fb4, Opts) of - Opts -> - %% Nope, run as usual, where we use error reason - %% to detect if we are on IPv6 or not... - case gen_tcp:connect(Host,Port, Opts) of - {ok, Socket} -> - tsp("connect success"), - {ok, Socket}; - {error, nxdomain} -> - tsp("connect error nxdomain when opts: ~p", [Opts]), - connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); - {error, eafnosupport} -> - tsp("connect error eafnosupport when opts: ~p", [Opts]), - connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); - {error, econnreset} -> - tsp("connect error econnreset when opts: ~p", [Opts]), - connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); - {error, enetunreach} -> - tsp("connect error eafnosupport when opts: ~p", [Opts]), - connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); - {error, {enfile,_}} -> - tsp("connect error enfile when opts: ~p", [Opts]), - {error, enfile}; - Error -> - tsp("connect(ip_conn) -> Unexpected error: " - "~n Error: ~p" - "~nwhen" - "~n Host: ~p" - "~n Port: ~p" - "~n Opts: ~p" - "~n", [Error, Host, Port, Opts]), - Error - end; + case gen_tcp:connect(Host, Port, Opts) of + {ok, Socket} -> + tsp("connect success"), + {ok, Socket}; - Opts2 -> - %% Yep, so try first with inet6 and if that fails inet - case gen_tcp:connect(Host, Port, [inet6|Opts2]) of - {ok, Socket} -> - tsp("connect success"), - {ok, Socket}; - {error, Reason_inet6} -> - tsp("inet6 connect failed: ~p", [Reason_inet6]), - case gen_tcp:connect(Host, Port, [inet|Opts2]) of - {ok, Socket} -> - tsp("connect success"), - {ok, Socket}; - {error, Reason_inet} -> - tsp("inet connect also failed: ~p", [Reason_inet]), - {error, {connect_failure, [{inet6, Reason_inet6}, - {inet, Reason_inet}]}} - end - end + {error, nxdomain} when Type =:= inet6 -> + tsp("connect error nxdomain when" + "~n Opts: ~p", [Opts]), + connect(ip_comm, Host, Port, Opts -- [inet6], inet); + {error, eafnosupport} when Type =:= inet6 -> + tsp("connect error eafnosupport when" + "~n Opts: ~p", [Opts]), + connect(ip_comm, Host, Port, Opts -- [inet6], inet); + {error, econnreset} when Type =:= inet6 -> + tsp("connect error econnreset when" + "~n Opts: ~p", [Opts]), + connect(ip_comm, Host, Port, Opts -- [inet6], inet); + {error, enetunreach} when Type =:= inet6 -> + tsp("connect error eafnosupport when" + "~n Opts: ~p", [Opts]), + connect(ip_comm, Host, Port, Opts -- [inet6], inet); + {error, econnrefused} when Type =:= inet6 -> + tsp("connect error econnrefused when" + "~n Opts: ~p", [Opts]), + connect(ip_comm, Host, Port, Opts -- [inet6], inet); + + Error -> + tsp("connect(ip_conn) -> Fatal connect error: " + "~n Error: ~p" + "~nwhen" + "~n Host: ~p" + "~n Port: ~p" + "~n Opts: ~p" + "~n Type: ~p" + "~n", [Error, Host, Port, Opts, Type]), + Error end. -- cgit v1.2.3 From 7b9b7c1cc416b0d5b1f2d5223ca5e012ddce0ea7 Mon Sep 17 00:00:00 2001 From: Jay Nelson Date: Mon, 5 Mar 2012 20:06:14 -0800 Subject: Add inets_sup:start_link/0 inets_app calls supervisor:start_link/3 directly rather than calling the root supervisor function inets_sup:start_link/0. This precludes using included_applications to start inets without having a wrapper function. This patch makes inets_app follow the standard OTP application structure. --- lib/inets/src/inets_app/inets_app.erl | 2 +- lib/inets/src/inets_app/inets_sup.erl | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/inets/src/inets_app/inets_app.erl b/lib/inets/src/inets_app/inets_app.erl index cae79a6767..77c39d85eb 100644 --- a/lib/inets/src/inets_app/inets_app.erl +++ b/lib/inets/src/inets_app/inets_app.erl @@ -24,7 +24,7 @@ -export([start/2, stop/1]). start(_Type, _State) -> - supervisor:start_link({local, inets_sup}, inets_sup, []). + inets_sup:start_link(). stop(_State) -> ok. diff --git a/lib/inets/src/inets_app/inets_sup.erl b/lib/inets/src/inets_app/inets_sup.erl index 20d5ef343e..0382362778 100644 --- a/lib/inets/src/inets_app/inets_sup.erl +++ b/lib/inets/src/inets_app/inets_sup.erl @@ -25,8 +25,18 @@ -behaviour(supervisor). +%% External API +-export([start_link/0]). + +%% Supervisor callbacks -export([init/1]). +%%%========================================================================= +%%% External functions +%%%========================================================================= +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + %%%========================================================================= %%% Supervisor callback %%%========================================================================= -- cgit v1.2.3 From 8f83fe72fe713a64e67490020e8d375b620f4abe Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 6 Mar 2012 12:50:14 +0100 Subject: [inets] Fixed release notes OTP-9960 --- lib/inets/doc/src/notes.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index 2c96c43efb..a14eb15de3 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -53,6 +53,17 @@

Own Id: OTP-9805

+ +

Improve inets support for inets as an included application.

+

inets_app calls supervisor:start_link/3 directly + rather than calling the root supervisor function + inets_sup:start_link/0. + This precludes using included_applications to start inets without + having a wrapper function.

+

Jay Nelson

+

Own Id: OTP-9960

+
+
-- cgit v1.2.3 From 5cefb654a99eae754badd417de493acc59f8efb3 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 13 Mar 2012 14:26:07 +0100 Subject: [inets/httpc] Add function to retreive current options Add function to retreive current options, httpc:get_options/1,2. OTP-9979 --- lib/inets/doc/src/httpc.xml | 31 ++++++++++++++- lib/inets/doc/src/notes.xml | 6 +++ lib/inets/src/http_client/httpc.erl | 60 +++++++++++++++++++++++++++-- lib/inets/src/http_client/httpc_manager.erl | 47 ++++++++++++++++++++++ lib/inets/src/inets_app/inets.appup.src | 10 +++++ lib/inets/test/httpc_SUITE.erl | 41 ++++++++++++-------- 6 files changed, 175 insertions(+), 20 deletions(-) diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml index 48a2089605..70c845bade 100644 --- a/lib/inets/doc/src/httpc.xml +++ b/lib/inets/doc/src/httpc.xml @@ -4,7 +4,7 @@
- 20042011 + 20042012 Ericsson AB. All Rights Reserved. @@ -541,6 +541,35 @@ apply(Module, Function, [ReplyInfo | Args]) default value of the max_sessions option.

+ + + + + + get_options(OptionItems) -> {ok, Values} | {error, Reason} + get_options(OptionItems, Profile) -> {ok, Values} | {error, Reason} + Gets the currently used options. + + OptionItems = all | [option_item()] + option_item() = proxy | + max_sessions | + keep_alive_timeout | + max_keep_alive_length | + pipeline_timeout | + max_pipeline_length | + cookies | + ipfamily | + ip | + port | + socket_opts | + verbose + Profile = profile() | pid() (when started stand_alone) + Values = [{option_item(), term()}] + Reason = term() + + +

Retrieves the options currently used by the client.

+
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index a14eb15de3..f2cd03b6a8 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -64,6 +64,12 @@

Own Id: OTP-9960

+ +

[httpc] Add function for retrieving current options, + get_options/1,2.

+

Own Id: OTP-9979

+
+
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl index ae87ceed93..5ed2d98ba6 100644 --- a/lib/inets/src/http_client/httpc.erl +++ b/lib/inets/src/http_client/httpc.erl @@ -31,8 +31,10 @@ -export([ request/1, request/2, request/4, request/5, cancel_request/1, cancel_request/2, - set_option/2, set_option/3, + set_option/2, set_option/3, set_options/1, set_options/2, + get_option/1, get_option/2, + get_options/1, get_options/2, store_cookies/2, store_cookies/3, cookie_header/1, cookie_header/2, cookie_header/3, which_cookies/0, which_cookies/1, @@ -230,7 +232,7 @@ cancel_request(RequestId, Profile) set_options(Options) -> set_options(Options, default_profile()). set_options(Options, Profile) when is_atom(Profile) orelse is_pid(Profile) -> - ?hcrt("set cookies", [{options, Options}, {profile, Profile}]), + ?hcrt("set options", [{options, Options}, {profile, Profile}]), case validate_options(Options) of {ok, Opts} -> try @@ -252,6 +254,58 @@ set_option(Key, Value, Profile) -> set_options([{Key, Value}], Profile). +%%-------------------------------------------------------------------------- +%% get_options(OptionItems) -> {ok, Values} | {error, Reason} +%% get_options(OptionItems, Profile) -> {ok, Values} | {error, Reason} +%% OptionItems - all | [option_item()] +%% option_item() - proxy | pipeline_timeout | max_pipeline_length | +%% keep_alive_timeout | max_keep_alive_length | +%% max_sessions | verbose | +%% cookies | ipfamily | ip | port | socket_opts +%% Profile - atom() +%% Values - [{option_item(), term()}] +%% Reason - term() +%% Description: Retrieves the current options. +%%------------------------------------------------------------------------- +get_options() -> + record_info(fields, options). + +get_options(Options) -> + get_options(Options, default_profile()). + +get_options(all = _Options, Profile) -> + get_options(get_options(), Profile); +get_options(Options, Profile) + when (is_list(Options) andalso + (is_atom(Profile) orelse is_pid(Profile))) -> + ?hcrt("get options", [{options, Options}, {profile, Profile}]), + case Options -- get_options() of + [] -> + try + begin + {ok, httpc_manager:get_options(Options, + profile_name(Profile))} + end + catch + exit:{noproc, _} -> + {error, inets_not_started} + end; + InvalidGetOptions -> + {error, {invalid_options, InvalidGetOptions}} + end. + +get_option(Key) -> + get_option(Key, default_profile()). + +get_option(Key, Profile) -> + case get_options([Key], Profile) of + {ok, [{Key, Value}]} -> + {ok, Value}; + Error -> + Error + end. + + %%-------------------------------------------------------------------------- %% store_cookies(SetCookieHeaders, Url [, Profile]) -> ok | {error, reason} %% @@ -347,7 +401,7 @@ which_cookies(Profile) -> %% info() -> list() %% info(Profile) -> list() %% -%% Description: Debug function, retreive info about the profile +%% Description: Debug function, retrieve info about the profile %%------------------------------------------------------------------------- info() -> info(default_profile()). diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl index 453081da21..33b5dfe046 100644 --- a/lib/inets/src/http_client/httpc_manager.erl +++ b/lib/inets/src/http_client/httpc_manager.erl @@ -37,6 +37,7 @@ update_session/4, delete_session/2, set_options/2, + get_options/2, store_cookies/3, which_cookies/1, which_cookies/2, which_cookies/3, reset_cookies/1, @@ -249,6 +250,21 @@ set_options(Options, ProfileName) -> cast(ProfileName, {set_options, Options}). +%%-------------------------------------------------------------------- +%% Function: get_options(OptionItems, ProfileName) -> Values +%% +%% OptionItems = [OptionItem] +%% OptionItem = Any or all fields of the current #options{} record +%% Values = [{OptionItem, Value}] +%% Value = term() +%% +%% Description: Gets the specified options used by the client. +%%-------------------------------------------------------------------- + +get_options(Options, ProfileName) -> + call(ProfileName, {get_options, Options}). + + %%-------------------------------------------------------------------- %% Function: store_cookies(Cookies, Address, ProfileName) -> ok %% @@ -439,6 +455,12 @@ handle_call({which_cookies, Url, Options}, _, {reply, ERROR, State} end; +handle_call({get_options, OptionItems}, _, #state{options = Options} = State) -> + ?hcrv("get options", [{option_items, OptionItems}]), + Reply = [{OptionItem, get_option(OptionItem, Options)} || OptionItem <- + OptionItems], + {reply, Reply, State}; + handle_call(info, _, State) -> ?hcrv("info", []), Info = get_manager_info(State), @@ -883,6 +905,31 @@ cast(ProfileName, Msg) -> gen_server:cast(ProfileName, Msg). +get_option(proxy, #options{proxy = Proxy}) -> + Proxy; +get_option(pipeline_timeout, #options{pipeline_timeout = Timeout}) -> + Timeout; +get_option(max_pipeline_length, #options{max_pipeline_length = Length}) -> + Length; +get_option(keep_alive_timeout, #options{keep_alive_timeout = Timeout}) -> + Timeout; +get_option(max_keep_alive_length, #options{max_keep_alive_length = Length}) -> + Length; +get_option(max_sessions, #options{max_sessions = MaxSessions}) -> + MaxSessions; +get_option(cookies, #options{cookies = Cookies}) -> + Cookies; +get_option(verbose, #options{verbose = Verbose}) -> + Verbose; +get_option(ipfamily, #options{ipfamily = IpFamily}) -> + IpFamily; +get_option(ip, #options{ip = IP}) -> + IP; +get_option(port, #options{port = Port}) -> + Port; +get_option(socket_opts, #options{socket_opts = SocketOpts}) -> + SocketOpts. + get_proxy(Opts, #options{proxy = Default}) -> proplists:get_value(proxy, Opts, Default). diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index d36fcf87d4..9dfa16b405 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -20,6 +20,9 @@ [ {"5.8.1", [ + {load_module, httpc, soft_purge, soft_purge, [httpc_manager]}, + {update, httpc_manager, soft, soft_purge, soft_purge, []}, + {load_module, inets_app, soft_purge, soft_purge, [inets_sup]}, {update, inets_sup, soft, soft_purge, soft_purge, []}, @@ -35,6 +38,8 @@ }, {"5.8", [ + {load_module, httpc, soft_purge, soft_purge, [httpc_manager]}, + {load_module, inets_app, soft_purge, soft_purge, [inets_sup]}, {update, inets_sup, soft, soft_purge, soft_purge, []}, @@ -63,6 +68,9 @@ [ {"5.8.1", [ + {load_module, httpc, soft_purge, soft_purge, [httpc_manager]}, + {update, httpc_manager, soft, soft_purge, soft_purge, []}, + {load_module, inets_app, soft_purge, soft_purge, [inets_sup]}, {update, inets_sup, soft, soft_purge, soft_purge, []}, @@ -78,6 +86,8 @@ }, {"5.8", [ + {load_module, httpc, soft_purge, soft_purge, [httpc_manager]}, + {load_module, inets_app, soft_purge, soft_purge, [inets_sup]}, {update, inets_sup, soft, soft_purge, soft_purge, []}, diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index a18d079426..61bb5214f3 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -275,20 +275,6 @@ init_per_testcase(Case, Timeout, Config) -> %% inets:enable_trace(max, io, httpc), %% inets:enable_trace(max, io, all), - %% - % Set default ipfamily to the same as the main server has by default - %% This makes the client try w/ ipv6 before falling back to ipv4, - %% as that is what the server is configured to do. - %% Note that this is required for the tests to run on *BSD w/ ipv6 enabled - %% as well as on Windows. The Linux behaviour of allowing ipv4 connects - %% to ipv6 sockets is not required or even encouraged. - - httpc:set_options([{ipfamily, inet6fb4}]), - - %% Note that the IPv6 trest case *must* use inet6, - %% so this value will be overwritten (see "ipv6_" below). - %% - NewConfig = case atom_to_list(Case) of [$s, $s, $l | _] -> @@ -371,7 +357,8 @@ init_per_testcase(Case, Timeout, Config) -> inets:start(httpc, [{profile, Profile}, {data_dir, PrivDir}], stand_alone), - httpc:set_options([{ipfamily, inet6}], ProfilePid), + ok = httpc:set_options([{ipfamily, inet6}], + ProfilePid), tsp("httpc profile pid: ~p", [ProfilePid]), [{watchdog, Dog}, {profile, ProfilePid}| TmpConfig] catch @@ -410,9 +397,31 @@ init_per_testcase(Case, Timeout, Config) -> [{watchdog, Dog}, {local_server, Server} | TmpConfig2] end, + %% + %% Set default ipfamily to the same as the main server has by default + %% This makes the client try w/ ipv6 before falling back to ipv4, + %% as that is what the server is configured to do. + %% Note that this is required for the tests to run on *BSD w/ ipv6 enabled + %% as well as on Windows. The Linux behaviour of allowing ipv4 connects + %% to ipv6 sockets is not required or even encouraged. + + tsp("init_per_testcase -> Options before ipfamily set: ~n~p", + [httpc:get_options(all)]), + ok = httpc:set_options([{ipfamily, inet6fb4}]), + tsp("init_per_testcase -> Options after ipfamily set: ~n~p", + [httpc:get_options(all)]), + + %% Note that the IPv6 test case(s) *must* use inet6, + %% so this value will be overwritten (see "ipv6_" below). + %% + %% This will fail for the ipv6_ - cases (but that is ok) ProxyExceptions = ["localhost", ?IPV6_LOCAL_HOST], - httpc:set_options([{proxy, {{?PROXY, ?PROXY_PORT}, ProxyExceptions}}]), + tsp("init_per_testcase -> Options before proxy set: ~n~p", + [httpc:get_options(all)]), + ok = httpc:set_options([{proxy, {{?PROXY, ?PROXY_PORT}, ProxyExceptions}}]), + tsp("init_per_testcase -> Options after proxy set: ~n~p", + [httpc:get_options(all)]), inets:enable_trace(max, io, httpc), %% inets:enable_trace(max, io, all), %% snmp:set_trace([gen_tcp]), -- cgit v1.2.3 From 1017c9b5629148f3d584434f1c351cf1e8dded24 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 14 Mar 2012 12:25:52 +0100 Subject: [inets/httpd] Fixed alias test cases Fixed the alias test cases where an invalid option was used. Also, hopefully improved error reporting in case connect fails. --- lib/inets/test/httpd_mod.erl | 9 +-------- lib/inets/test/httpd_test_lib.erl | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/inets/test/httpd_mod.erl b/lib/inets/test/httpd_mod.erl index 23551ab125..cb1214b7fb 100644 --- a/lib/inets/test/httpd_mod.erl +++ b/lib/inets/test/httpd_mod.erl @@ -41,14 +41,7 @@ alias(Type, Port, Host, Node) -> %% This is very crude, but... tsp("alias -> Has IPv6 support: ~p", [inets_test_lib:has_ipv6_support()]), - Opts = case os:type() of - {win32, _} -> - [inet6fb4]; - _ -> - [] - end, - tsp("alias -> Opts: ~p", [Opts]), - + Opts = [], ok = httpd_test_lib:verify_request(Type, Host, Port, Opts, Node, "GET /pics/icon.sheet.gif " "HTTP/1.0\r\n\r\n", diff --git a/lib/inets/test/httpd_test_lib.erl b/lib/inets/test/httpd_test_lib.erl index ed6ee315b3..3e1213376d 100644 --- a/lib/inets/test/httpd_test_lib.erl +++ b/lib/inets/test/httpd_test_lib.erl @@ -101,7 +101,7 @@ verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options, Ti "~n Options: ~p" "~n TimeOut: ~p", [SocketType, Host, Port, TranspOpts, Node, Options, TimeOut]), - case (catch inets_test_lib:connect_bin(SocketType, Host, Port, TranspOpts)) of + try inets_test_lib:connect_bin(SocketType, Host, Port, TranspOpts) of {ok, Socket} -> tsp("verify_request -> connected - now send message"), SendRes = inets_test_lib:send(SocketType, Socket, RequestStr), @@ -132,10 +132,22 @@ verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options, Ti end; ConnectError -> - tsp("verify_request -> connect failed: " + tsp("verify_request -> connect error: " "~n ~p" "~n", [ConnectError]), - tsf({connect_failure, ConnectError}) + tsf({connect_error, ConnectError, + [SocketType, Host, Port, TranspOpts]}) + catch + T:E -> + tsp("verify_request -> connect failed: " + "~n E: ~p" + "~n T: ~p" + "~n", [E, T]), + tsf({connect_failure, + [{type, T}, + {error, E}, + {stacktrace, erlang:get_stacktrace()}, + {args, [SocketType, Host, Port, TranspOpts]}]}) end. request(#state{mfa = {Module, Function, Args}, -- cgit v1.2.3 From 54ca9088b4a83b1f7dc22db7ec4c16607fdd8850 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 14 Mar 2012 18:09:12 +0100 Subject: [inets] Initial proposal of module http_uri MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This version of the module was provided by Johan Tjäder. It adds support for more methods (more than http and https). OTP-9983 --- lib/inets/src/http_lib/http_uri.erl | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/lib/inets/src/http_lib/http_uri.erl b/lib/inets/src/http_lib/http_uri.erl index 32c6305a79..d0d1033cf6 100644 --- a/lib/inets/src/http_lib/http_uri.erl +++ b/lib/inets/src/http_lib/http_uri.erl @@ -72,12 +72,15 @@ parse_scheme(AbsURI) -> {error, no_scheme} -> {error, no_scheme}; {StrScheme, Rest} -> - case list_to_atom(http_util:to_lower(StrScheme)) of - Scheme when (Scheme =:= http) orelse (Scheme =:= https) -> - {Scheme, Rest}; - Scheme -> - {error, {not_supported_scheme, Scheme}} - end + %% case list_to_atom(http_util:to_lower(StrScheme)) of + %% Scheme when (Scheme =:= http) orelse (Scheme =:= https) -> + %% {Scheme, Rest}; + %% Scheme -> + %% {error, {not_supported_scheme, Scheme}} + %% end + + %% Allow all schemes even if they are unknown + {list_to_atom(http_util:to_lower(StrScheme)), Rest} end. parse_uri_rest(Scheme, "//" ++ URIPart, Opts) -> @@ -133,10 +136,21 @@ maybe_ipv6_host_with_brackets(Host, Opts) -> Host end. -default_port(http) -> +default_port(http) -> 80; -default_port(https) -> - 443. +default_port(https) -> + 443; + +%%% Added some additional default ports +%%% Other protocols would have to be handled by the calling function +default_port(ftp) -> 21; +default_port(ssh) -> 22; +default_port(sftp) -> 22; +default_port(tftp) -> 69; + +default_port(_) -> + undefined. + int_port(Port) when is_integer(Port) -> Port; -- cgit v1.2.3 From 0c11d7235ed1f0f5c595cf3d9a433adf9c61cc8c Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 14 Mar 2012 18:51:03 +0100 Subject: [inets] A more general version of http_uri:parse OTP-9983 --- lib/inets/src/http_client/httpc.erl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl index 5ed2d98ba6..2c51c2081c 100644 --- a/lib/inets/src/http_client/httpc.erl +++ b/lib/inets/src/http_client/httpc.erl @@ -585,6 +585,10 @@ maybe_encode_uri(#http_options{url_encode = true}, URI) -> maybe_encode_uri(_, URI) -> URI. +uri_parse(AbsURI) -> + http_uri:parse(AbsURI, [{scheme_defaults, [{http, 80}, {https, 443}]}]). + + mk_chunkify_fun(ProcessBody) -> fun(eof_body) -> eof; -- cgit v1.2.3 From a366623c674e993667fedbe01ad52dc4fab5b4f0 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 15 Mar 2012 11:59:40 +0100 Subject: [inets] The module http_uri now officially supported The module http_uri now officially supported. Also, the http_uri:parse/1,2 function has been extended with more scheme support and a way to provide your own scheme info. OTP-9983 --- lib/inets/doc/src/Makefile | 1 + lib/inets/doc/src/http_uri.xml | 160 +++++++++++++++++++++++++++ lib/inets/doc/src/notes.xml | 12 ++ lib/inets/doc/src/ref_man.xml | 9 +- lib/inets/src/http_client/httpc.erl | 26 +++-- lib/inets/src/http_client/httpc_manager.erl | 15 ++- lib/inets/src/http_client/httpc_response.erl | 16 ++- lib/inets/src/http_lib/http_uri.erl | 143 ++++++++++++++++-------- lib/inets/test/httpc_SUITE.erl | 6 +- 9 files changed, 326 insertions(+), 62 deletions(-) create mode 100644 lib/inets/doc/src/http_uri.xml diff --git a/lib/inets/doc/src/Makefile b/lib/inets/doc/src/Makefile index 53d505b102..c4152a1d72 100644 --- a/lib/inets/doc/src/Makefile +++ b/lib/inets/doc/src/Makefile @@ -48,6 +48,7 @@ XML_REF3_FILES = \ inets.xml \ ftp.xml \ tftp.xml \ + http_uri.xml\ httpc.xml\ httpd.xml \ httpd_conf.xml \ diff --git a/lib/inets/doc/src/http_uri.xml b/lib/inets/doc/src/http_uri.xml new file mode 100644 index 0000000000..bd31ae42d2 --- /dev/null +++ b/lib/inets/doc/src/http_uri.xml @@ -0,0 +1,160 @@ + + + + +
+ + 20122012 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + http_uri + + + + + +
+ + http_uri + URI utility module + + +

This module provides utility functions for working with URIs, + according to RFC 3986.

+ +
+ +
+ COMMON DATA TYPES +

Type definitions that are used more than once in + this module:

+ + +
+ +
+ URI DATA TYPES +

Type definitions that are related to URI:

+

For more information about URI, see RFC 3986.

+ + + + +
+ + + + scheme_defaults() -> SchemeDefaults + A list of scheme and their default ports + + SchemeDefaults = [{scheme(), default_scheme_port_number()}] + default_scheme_port_number() = pos_integer() + + +

This function provides a list of the scheme and their default + port numbers currently supported (by default) by this utility.

+ + +
+
+ + + parse(URI) -> {ok, Result} | {error, Reason} + parse(URI, Options) -> {ok, Result} | {error, Reason} + Parse an URI + + URI = uri() + Options = [Option] + Option = {ipv6_host_with_brackets, boolean()} | + {scheme_defaults, scheme_defaults()}] + Result = {Scheme, UserInfo, Host, Port, Path, Query} + UserInfo = user_info() + Host = host() + Port = pos_integer() + Path = path() + Query = query() + Reason = term() + + +

This function is used to parse an URI. If no scheme defaults + are provided, the value of + scheme_defaults + function will be used.

+ +

Note that when parsing an URI with an unknown scheme (that is, + a scheme not found in the scheme defaults) a port number must be + provided or else the parsing will fail.

+ + +
+
+ + + encode(URI) -> HexEncodedURI + + Hex encode an URI + + URI = uri() + HexEncodedURI = string() - Hex encoded uri + + + +

Hex encode an URI.

+ + +
+
+ + + decode(HexEncodedURI) -> URI + + Decode a hex encoded URI + + HexEncodedURI = string() - A possibly hex encoded uri + URI = uri() + + + +

Decode a possibly hex encoded URI.

+ +
+
+ +
+ + + +
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index f2cd03b6a8..dfdeb4016c 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -70,6 +70,18 @@

Own Id: OTP-9979

+ +

Utility module + http_uri + now officially supported.

+

Also, the + parse + function has been extended with more + scheme support and a way to provide your own scheme info.

+

Own Id: OTP-9983

+

Aux Id: Seq 12022

+
+ diff --git a/lib/inets/doc/src/ref_man.xml b/lib/inets/doc/src/ref_man.xml index 45d5dfcd0e..e44829827c 100644 --- a/lib/inets/doc/src/ref_man.xml +++ b/lib/inets/doc/src/ref_man.xml @@ -1,10 +1,10 @@ - +
- 19972010 + 19972012 Ericsson AB. All Rights Reserved. @@ -30,8 +30,8 @@

Inets is a container for Internet clients and - servers. Currently a FTP client, a HTTP client and server, and - a tftp client and server has been incorporated in Inets.

+ servers. Currently a FTP client, a HTTP client and server, and + a tftp client and server has been incorporated in Inets.

@@ -45,6 +45,7 @@ +
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl index 2c51c2081c..0a30fe1e20 100644 --- a/lib/inets/src/http_client/httpc.erl +++ b/lib/inets/src/http_client/httpc.erl @@ -158,7 +158,7 @@ request(Method, {http_options, HTTPOptions}, {options, Options}, {profile, Profile}]), - case http_uri:parse(Url, Options) of + case uri_parse(Url, Options) of {error, Reason} -> {error, Reason}; {ok, ParsedUrl} -> @@ -179,7 +179,7 @@ request(Method, {http_options, HTTPOptions}, {options, Options}, {profile, Profile}]), - case http_uri:parse(Url, Options) of + case uri_parse(Url, Options) of {error, Reason} -> {error, Reason}; {ok, ParsedUrl} -> @@ -328,7 +328,7 @@ store_cookies(SetCookieHeaders, Url, Profile) %% Since the Address part is not actually used %% by the manager when storing cookies, we dont %% care about ipv6-host-with-brackets. - {ok, {_, _, Host, Port, Path, _}} = http_uri:parse(Url), + {ok, {_, _, Host, Port, Path, _}} = uri_parse(Url), Address = {Host, Port}, ProfileName = profile_name(Profile), Cookies = httpc_cookie:cookies(SetCookieHeaders, Path, Host), @@ -585,10 +585,6 @@ maybe_encode_uri(#http_options{url_encode = true}, URI) -> maybe_encode_uri(_, URI) -> URI. -uri_parse(AbsURI) -> - http_uri:parse(AbsURI, [{scheme_defaults, [{http, 80}, {https, 443}]}]). - - mk_chunkify_fun(ProcessBody) -> fun(eof_body) -> eof; @@ -1202,6 +1198,22 @@ validate_headers(RequestHeaders, _, _) -> RequestHeaders. +%%-------------------------------------------------------------------------- +%% These functions is just simple wrappers to parse specifically HTTP URIs +%%-------------------------------------------------------------------------- + +scheme_defaults() -> + [{http, 80}, {https, 443}]. + +uri_parse(URI) -> + http_uri:parse(URI, [{scheme_defaults, scheme_defaults()}]). + +uri_parse(URI, Opts) -> + http_uri:parse(URI, [{scheme_defaults, scheme_defaults()} | Opts]). + + +%%-------------------------------------------------------------------------- + child_name2info(undefined) -> {error, no_such_service}; child_name2info(httpc_manager) -> diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl index 33b5dfe046..b225b43214 100644 --- a/lib/inets/src/http_client/httpc_manager.erl +++ b/lib/inets/src/http_client/httpc_manager.erl @@ -446,7 +446,7 @@ handle_call(which_cookies, _, #state{cookie_db = CookieDb} = State) -> handle_call({which_cookies, Url, Options}, _, #state{cookie_db = CookieDb} = State) -> ?hcrv("which cookies", [{url, Url}, {options, Options}]), - case http_uri:parse(Url, Options) of + case uri_parse(Url, Options) of {ok, {Scheme, _, Host, Port, Path, _}} -> CookieHeaders = httpc_cookie:header(CookieDb, Scheme, {Host, Port}, Path), @@ -894,6 +894,19 @@ make_db_name(ProfileName, Post) -> list_to_atom(atom_to_list(ProfileName) ++ Post). +%%-------------------------------------------------------------------------- +%% These functions is just simple wrappers to parse specifically HTTP URIs +%%-------------------------------------------------------------------------- + +scheme_defaults() -> + [{http, 80}, {https, 443}]. + +uri_parse(URI, Opts) -> + http_uri:parse(URI, [{scheme_defaults, scheme_defaults()} | Opts]). + + +%%-------------------------------------------------------------------------- + call(ProfileName, Msg) -> Timeout = infinity, diff --git a/lib/inets/src/http_client/httpc_response.erl b/lib/inets/src/http_client/httpc_response.erl index 919115a23a..23924e355e 100644 --- a/lib/inets/src/http_client/httpc_response.erl +++ b/lib/inets/src/http_client/httpc_response.erl @@ -342,7 +342,7 @@ redirect(Response = {StatusLine, Headers, Body}, Request) -> RedirUrl -> UrlParseOpts = [{ipv6_host_with_brackets, Request#request.ipv6_host_with_brackets}], - case http_uri:parse(RedirUrl, UrlParseOpts) of + case uri_parse(RedirUrl, UrlParseOpts) of {error, no_scheme} when (Request#request.settings)#http_options.relaxed -> NewLocation = fix_relative_uri(Request, RedirUrl), @@ -437,3 +437,17 @@ format_response({StatusLine, Headers, Body}) -> end, {{StatusLine, http_response:header_list(Headers), NewBody}, Data}. +%%-------------------------------------------------------------------------- +%% These functions is just simple wrappers to parse specifically HTTP URIs +%%-------------------------------------------------------------------------- + +scheme_defaults() -> + [{http, 80}, {https, 443}]. + +uri_parse(URI, Opts) -> + http_uri:parse(URI, [{scheme_defaults, scheme_defaults()} | Opts]). + + +%%-------------------------------------------------------------------------- + + diff --git a/lib/inets/src/http_lib/http_uri.erl b/lib/inets/src/http_lib/http_uri.erl index d0d1033cf6..5962001c3a 100644 --- a/lib/inets/src/http_lib/http_uri.erl +++ b/lib/inets/src/http_lib/http_uri.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2011. All Rights Reserved. +%% Copyright Ericsson AB 2006-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -17,39 +17,95 @@ %% %CopyrightEnd% %% %% -%% RFC 3986 +%% This is from chapter 3, Syntax Components, of RFC 3986: +%% +%% The generic URI syntax consists of a hierarchical sequence of +%% components referred to as the scheme, authority, path, query, and +%% fragment. +%% +%% URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] +%% +%% hier-part = "//" authority path-abempty +%% / path-absolute +%% / path-rootless +%% / path-empty +%% +%% The scheme and path components are required, though the path may be +%% empty (no characters). When authority is present, the path must +%% either be empty or begin with a slash ("/") character. When +%% authority is not present, the path cannot begin with two slash +%% characters ("//"). These restrictions result in five different ABNF +%% rules for a path (Section 3.3), only one of which will match any +%% given URI reference. +%% +%% The following are two example URIs and their component parts: +%% +%% foo://example.com:8042/over/there?name=ferret#nose +%% \_/ \______________/\_________/ \_________/ \__/ +%% | | | | | +%% scheme authority path query fragment +%% | _____________________|__ +%% / \ / \ +%% urn:example:animal:ferret:nose +%% +%% scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) +%% authority = [ userinfo "@" ] host [ ":" port ] +%% userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) +%% %% -module(http_uri). -export([parse/1, parse/2, + scheme_defaults/0, encode/1, decode/1]). +-export_type([scheme/0, default_scheme_port_number/0]). + %%%========================================================================= %%% API %%%========================================================================= + +-type scheme() :: atom(). +-type default_scheme_port_number() :: pos_integer(). + +-spec scheme_defaults() -> + [{scheme(), default_scheme_port_number()}]. + +scheme_defaults() -> + [{http, 80}, + {https, 443}, + {ftp, 21}, + {ssh, 22}, + {sftp, 22}, + {tftp, 69}]. + parse(AbsURI) -> parse(AbsURI, []). parse(AbsURI, Opts) -> - case parse_scheme(AbsURI) of + case parse_scheme(AbsURI, Opts) of {error, Reason} -> {error, Reason}; - {Scheme, Rest} -> - case (catch parse_uri_rest(Scheme, Rest, Opts)) of - {UserInfo, Host, Port, Path, Query} -> + {Scheme, DefaultPort, Rest} -> + case (catch parse_uri_rest(Scheme, DefaultPort, Rest, Opts)) of + {ok, {UserInfo, Host, Port, Path, Query}} -> {ok, {Scheme, UserInfo, Host, Port, Path, Query}}; + {error, Reason} -> + {error, {Reason, Scheme, AbsURI}}; _ -> - {error, {malformed_url, AbsURI}} + {error, {malformed_url, Scheme, AbsURI}} end end. +reserved() -> + sets:from_list([$;, $:, $@, $&, $=, $+, $,, $/, $?, + $#, $[, $], $<, $>, $\", ${, $}, $|, + $\\, $', $^, $%, $ ]). + encode(URI) -> - Reserved = sets:from_list([$;, $:, $@, $&, $=, $+, $,, $/, $?, - $#, $[, $], $<, $>, $\", ${, $}, $|, - $\\, $', $^, $%, $ ]), - %% lists:append(lists:map(fun(Char) -> uri_encode(Char, Reserved) end, URI)). + Reserved = reserved(), lists:append([uri_encode(Char, Reserved) || Char <- URI]). decode(String) -> @@ -67,23 +123,31 @@ do_decode([]) -> %%% Internal functions %%%======================================================================== -parse_scheme(AbsURI) -> +which_scheme_defaults(Opts) -> + Key = scheme_defaults, + case lists:keysearch(Key, 1, Opts) of + {value, {Key, SchemeDefaults}} -> + SchemeDefaults; + false -> + scheme_defaults() + end. + +parse_scheme(AbsURI, Opts) -> case split_uri(AbsURI, ":", {error, no_scheme}, 1, 1) of {error, no_scheme} -> {error, no_scheme}; - {StrScheme, Rest} -> - %% case list_to_atom(http_util:to_lower(StrScheme)) of - %% Scheme when (Scheme =:= http) orelse (Scheme =:= https) -> - %% {Scheme, Rest}; - %% Scheme -> - %% {error, {not_supported_scheme, Scheme}} - %% end - - %% Allow all schemes even if they are unknown - {list_to_atom(http_util:to_lower(StrScheme)), Rest} + {SchemeStr, Rest} -> + Scheme = list_to_atom(http_util:to_lower(SchemeStr)), + SchemeDefaults = which_scheme_defaults(Opts), + case lists:keysearch(Scheme, 1, SchemeDefaults) of + {value, {Scheme, DefaultPort}} -> + {Scheme, DefaultPort, Rest}; + false -> + {Scheme, no_default_port, Rest} + end end. -parse_uri_rest(Scheme, "//" ++ URIPart, Opts) -> +parse_uri_rest(Scheme, DefaultPort, "//" ++ URIPart, Opts) -> {Authority, PathQuery} = case split_uri(URIPart, "/", URIPart, 1, 0) of Split = {_, _} -> @@ -96,26 +160,25 @@ parse_uri_rest(Scheme, "//" ++ URIPart, Opts) -> {URIPart,""} end end, - {UserInfo, HostPort} = split_uri(Authority, "@", {"", Authority}, 1, 1), - {Host, Port} = parse_host_port(Scheme, HostPort, Opts), + {Host, Port} = parse_host_port(Scheme, DefaultPort, HostPort, Opts), {Path, Query} = parse_path_query(PathQuery), - {UserInfo, Host, Port, Path, Query}. + {ok, {UserInfo, Host, Port, Path, Query}}. parse_path_query(PathQuery) -> {Path, Query} = split_uri(PathQuery, "\\?", {PathQuery, ""}, 1, 0), {path(Path), Query}. -parse_host_port(Scheme,"[" ++ HostPort, Opts) -> %ipv6 - DefaultPort = default_port(Scheme), +%% In this version of the function, we no longer need +%% the Scheme argument, but just in case... +parse_host_port(_Scheme, DefaultPort, "[" ++ HostPort, Opts) -> %ipv6 {Host, ColonPort} = split_uri(HostPort, "\\]", {HostPort, ""}, 1, 1), Host2 = maybe_ipv6_host_with_brackets(Host, Opts), {_, Port} = split_uri(ColonPort, ":", {"", DefaultPort}, 0, 1), {Host2, int_port(Port)}; -parse_host_port(Scheme, HostPort, _Opts) -> - DefaultPort = default_port(Scheme), +parse_host_port(_Scheme, DefaultPort, HostPort, _Opts) -> {Host, Port} = split_uri(HostPort, ":", {HostPort, DefaultPort}, 1, 1), {Host, int_port(Port)}. @@ -136,26 +199,14 @@ maybe_ipv6_host_with_brackets(Host, Opts) -> Host end. -default_port(http) -> - 80; -default_port(https) -> - 443; - -%%% Added some additional default ports -%%% Other protocols would have to be handled by the calling function -default_port(ftp) -> 21; -default_port(ssh) -> 22; -default_port(sftp) -> 22; -default_port(tftp) -> 69; - -default_port(_) -> - undefined. - int_port(Port) when is_integer(Port) -> Port; int_port(Port) when is_list(Port) -> - list_to_integer(Port). + list_to_integer(Port); +%% This is the case where no port was found and there was no default port +int_port(no_default_port) -> + throw({error, no_default_port}). path("") -> "/"; diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 61bb5214f3..a116edef77 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -1974,7 +1974,7 @@ parse_url(Config) when is_list(Config) -> http_uri:parse("http://[2010:836B:4179::836B:4179]/foobar.html", [{foo, false}]), {error, - {malformed_url,"http://2010:836B:4179::836B:4179/foobar.html"}} = + {malformed_url, _, "http://2010:836B:4179::836B:4179/foobar.html"}} = http_uri:parse("http://2010:836B:4179::836B:4179/foobar.html"), %% ipv4 @@ -1990,8 +1990,8 @@ parse_url(Config) when is_list(Config) -> http_uri:parse("http://nisse:foobar@localhost:8888/foobar.html"), %% Scheme error - {error,no_scheme} = http_uri:parse("localhost/foobar.html"), - {error,{not_supported_scheme,localhost}} = + {error, no_scheme} = http_uri:parse("localhost/foobar.html"), + {error, {malformed_url, _, _}} = http_uri:parse("localhost:8888/foobar.html"), %% Query -- cgit v1.2.3 From dbf9c223cf7efd8fc6143b573fcc12637d5ae9ae Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 15 Mar 2012 12:00:58 +0100 Subject: [inets] Some documentation cleanup OTP-9983 --- lib/inets/doc/src/book.xml | 4 +- lib/inets/doc/src/fascicules.xml | 2 +- lib/inets/doc/src/ftp_client.xml | 4 +- lib/inets/doc/src/httpd_conf.xml | 58 ++++++---- lib/inets/doc/src/httpd_socket.xml | 29 +++-- lib/inets/doc/src/httpd_util.xml | 4 +- lib/inets/doc/src/inets_services.xml | 4 +- lib/inets/doc/src/mod_alias.xml | 92 +++++++++------ lib/inets/doc/src/mod_auth.xml | 133 +++++++++++++-------- lib/inets/doc/src/notes_history.xml | 4 +- lib/inets/doc/src/part.xml | 4 +- lib/inets/doc/src/part_notes.xml | 4 +- lib/inets/doc/src/part_notes_history.xml | 4 +- lib/inets/doc/src/tftp.xml | 191 +++++++++++++++++++------------ 14 files changed, 331 insertions(+), 206 deletions(-) diff --git a/lib/inets/doc/src/book.xml b/lib/inets/doc/src/book.xml index 7da0abd98f..51cbb2d963 100644 --- a/lib/inets/doc/src/book.xml +++ b/lib/inets/doc/src/book.xml @@ -1,10 +1,10 @@ - +
- 19972009 + 19972012 Ericsson AB. All Rights Reserved. diff --git a/lib/inets/doc/src/fascicules.xml b/lib/inets/doc/src/fascicules.xml index 101e745722..ea3b988882 100644 --- a/lib/inets/doc/src/fascicules.xml +++ b/lib/inets/doc/src/fascicules.xml @@ -1,4 +1,4 @@ - + diff --git a/lib/inets/doc/src/ftp_client.xml b/lib/inets/doc/src/ftp_client.xml index 7f62a453a6..b44674d997 100644 --- a/lib/inets/doc/src/ftp_client.xml +++ b/lib/inets/doc/src/ftp_client.xml @@ -1,10 +1,10 @@ - +
- 20042009 + 20042012 Ericsson AB. All Rights Reserved. diff --git a/lib/inets/doc/src/httpd_conf.xml b/lib/inets/doc/src/httpd_conf.xml index a1ad76a8ae..fc34f14ec3 100644 --- a/lib/inets/doc/src/httpd_conf.xml +++ b/lib/inets/doc/src/httpd_conf.xml @@ -1,10 +1,10 @@ - +
- 19972009 + 19972012 Ericsson AB. All Rights Reserved. @@ -33,11 +33,14 @@ Web server API programmer.

This module provides the Erlang Webserver API programmer with - utility functions for adding run-time configuration directives.

+ utility functions for adding run-time configuration directives.

+ +
+ - check_enum(EnumString,ValidEnumStrings) -> Result + check_enum(EnumString, ValidEnumStrings) -> Result Check if string is a valid enumeration. EnumString = string() @@ -47,10 +50,13 @@

check_enum/2 checks if EnumString is a valid - enumeration of ValidEnumStrings in which case it is - returned as an atom.

+ enumeration of ValidEnumStrings in which case it is + returned as an atom.

+ +
+ clean(String) -> Stripped Remove leading and/or trailing white spaces. @@ -60,9 +66,12 @@

clean/1 removes leading and/or trailing white spaces - from String.

+ from String.

+ +
+ custom_clean(String,Before,After) -> Stripped Remove leading and/or trailing white spaces and custom characters. @@ -73,11 +82,14 @@

custom_clean/3 removes leading and/or trailing white - spaces and custom characters from String. Before - and After are regular expressions, as defined in - regexp(3), describing the custom characters.

+ spaces and custom characters from String. Before + and After are regular expressions, as defined in + regexp(3), describing the custom characters.

+ +
+ is_directory(FilePath) -> Result Check if a file path is a directory. @@ -91,13 +103,16 @@

is_directory/1 checks if FilePath is a - directory in which case it is returned. Please read - file(3) for a description of enoent, - eaccess and enotdir. The definition of - the file info record can be found by including file.hrl - from the kernel application, see file(3).

+ directory in which case it is returned. Please read + file(3) for a description of enoent, + eaccess and enotdir. The definition of + the file info record can be found by including file.hrl + from the kernel application, see file(3).

+ +
+ is_file(FilePath) -> Result Check if a file path is a regular file. @@ -111,13 +126,16 @@

is_file/1 checks if FilePath is a regular - file in which case it is returned. Read file(3) for a - description of enoent, eaccess and - enotdir. The definition of the file info record can be - found by including file.hrl from the kernel application, - see file(3).

+ file in which case it is returned. Read file(3) for a + description of enoent, eaccess and + enotdir. The definition of the file info record can be + found by including file.hrl from the kernel application, + see file(3).

+ +
+ make_integer(String) -> Result Return an integer representation of a string. diff --git a/lib/inets/doc/src/httpd_socket.xml b/lib/inets/doc/src/httpd_socket.xml index fba1a58d3a..58cd2ec575 100644 --- a/lib/inets/doc/src/httpd_socket.xml +++ b/lib/inets/doc/src/httpd_socket.xml @@ -1,10 +1,10 @@ - +
- 19972009 + 19972012 Ericsson AB. All Rights Reserved. @@ -33,10 +33,13 @@ Web server API programmer.

This module provides the Erlang Web server API module programmer - with utility functions for generic sockets communication. The - appropriate communication mechanism is transparently used, that - is ip_comm or ssl.

+ with utility functions for generic sockets communication. The + appropriate communication mechanism is transparently used, that + is ip_comm or ssl.

+ +
+ deliver(SocketType, Socket, Data) -> Result @@ -50,11 +53,14 @@

deliver/3 sends the Binary over the - Socket using the specified SocketType. Socket - and SocketType should be the socket and the socket_type form - the mod record as defined in httpd.hrl

+ Socket using the specified SocketType. Socket + and SocketType should be the socket and the socket_type form + the mod record as defined in httpd.hrl

+ +
+ peername(SocketType,Socket) -> {Port,IPAddress} Return the port and IP-address of the remote socket. @@ -67,9 +73,12 @@

peername/3 returns the Port and - IPAddress of the remote Socket.

+ IPAddress of the remote Socket.

+ +
+ resolve() -> HostName Return the official name of the current host. @@ -79,7 +88,7 @@

resolve/0 returns the official HostName of - the current host.

+ the current host.

diff --git a/lib/inets/doc/src/httpd_util.xml b/lib/inets/doc/src/httpd_util.xml index 6ac2b13c72..9f290084d2 100644 --- a/lib/inets/doc/src/httpd_util.xml +++ b/lib/inets/doc/src/httpd_util.xml @@ -1,10 +1,10 @@ - +
- 19972010 + 19972012 Ericsson AB. All Rights Reserved. diff --git a/lib/inets/doc/src/inets_services.xml b/lib/inets/doc/src/inets_services.xml index c274d67f19..e282050b12 100644 --- a/lib/inets/doc/src/inets_services.xml +++ b/lib/inets/doc/src/inets_services.xml @@ -1,10 +1,10 @@ - +
- 19972009 + 19972012 Ericsson AB. All Rights Reserved. diff --git a/lib/inets/doc/src/mod_alias.xml b/lib/inets/doc/src/mod_alias.xml index c783b99b23..265a1b8e76 100644 --- a/lib/inets/doc/src/mod_alias.xml +++ b/lib/inets/doc/src/mod_alias.xml @@ -1,10 +1,10 @@ - +
- 19972009 + 19972012 Ericsson AB. All Rights Reserved. @@ -32,8 +32,11 @@ URL aliasing.

Erlang Webserver Server internal API for handling of things - such as interaction data exported by the mod_alias module.

+ such as interaction data exported by the mod_alias module.

+ +
+ default_index(ConfigDB, Path) -> NewPath @@ -45,17 +48,20 @@

If Path is a directory, default_index/2, it starts - searching for resources or files that are specified in the config - directive DirectoryIndex. - If an appropriate resource or file is found, it is appended to - the end of Path and then returned. Path is - returned unaltered, if no appropriate - file is found, or if Path is not a directory. - config_db() is the server config file in ETS table format - as described in - Inets Users Guide..

+ searching for resources or files that are specified in the config + directive DirectoryIndex. + If an appropriate resource or file is found, it is appended to + the end of Path and then returned. Path is + returned unaltered, if no appropriate + file is found, or if Path is not a directory. + config_db() is the server config file in ETS table format + as described in + Inets Users Guide..

+ +
+ path(PathData, ConfigDB, RequestURI) -> Path Return the actual file path to a URL. @@ -67,15 +73,19 @@

path/3 returns the actual file Path in the - RequestURI (See RFC 1945). If the interaction data - {real_name,{Path,AfterPath}} has been exported by - mod_alias; - Path is returned. If no interaction data has been - exported, ServerRoot is used to - generate a file Path. config_db() and - interaction_data() are as defined in Inets Users Guide.

+ RequestURI (See RFC 1945). If the interaction data + {real_name,{Path,AfterPath}} has been exported by + mod_alias; + Path is returned. If no interaction data has been + exported, ServerRoot is used to + generate a file Path. config_db() and + interaction_data() are as defined in + Inets Users Guide.

+ +
+ real_name(ConfigDB, RequestURI, Aliases) -> Ret Expand a request uri using Alias config directives. @@ -89,18 +99,24 @@

real_name/3 traverses Aliases, typically - extracted from ConfigDB, and matches each - FakeName with RequestURI. If a match is found - FakeName is replaced with RealName in the - match. The resulting path is split into two parts, that - is ShortPath and AfterPath as defined in httpd_util:split_path/1. - Path is generated from ShortPath, that is - the result from default_index/2 with - ShortPath as an argument. - config_db() is the server config file in ETS table - format as described in Inets User Guide..

+ extracted from ConfigDB, and matches each + FakeName with RequestURI. If a match is found + FakeName is replaced with RealName in the + match. The resulting path is split into two parts, that + is ShortPath and AfterPath as defined in + httpd_util:split_path/1. + Path is generated from ShortPath, that is + the result from + default_index/2 with + ShortPath as an argument. + config_db() is the server config file in ETS table + format as described in + Inets User Guide..

+ +
+ real_script_name(ConfigDB,RequestURI,ScriptAliases) -> Ret Expand a request uri using ScriptAlias config directives. @@ -114,15 +130,15 @@

real_name/3 traverses ScriptAliases, - typically extracted from ConfigDB, and matches each - FakeName with RequestURI. If a match is found - FakeName is replaced with RealName in the - match. If the resulting match is not an executable script - not_a_script is returned. If it is a script the - resulting script path is in two parts, that is - ShortPath and AfterPath as defined in httpd_util:split_script_path/1. - config_db() is the server config file in ETS table - format as described in Inets Users Guide..

+ typically extracted from ConfigDB, and matches each + FakeName with RequestURI. If a match is found + FakeName is replaced with RealName in the + match. If the resulting match is not an executable script + not_a_script is returned. If it is a script the + resulting script path is in two parts, that is + ShortPath and AfterPath as defined in httpd_util:split_script_path/1. + config_db() is the server config file in ETS table + format as described in Inets Users Guide..

diff --git a/lib/inets/doc/src/mod_auth.xml b/lib/inets/doc/src/mod_auth.xml index 2134ebeeae..7801567862 100644 --- a/lib/inets/doc/src/mod_auth.xml +++ b/lib/inets/doc/src/mod_auth.xml @@ -1,4 +1,4 @@ - + @@ -32,8 +32,11 @@ User authentication using text files, dets or mnesia database.

This module provides for basic user authentication using - textual files, dets databases as well as mnesia databases.

+ textual files, dets databases as well as mnesia databases.

+ +
+ add_user(UserName, Options) -> true| {error, Reason} @@ -55,12 +58,17 @@ -

add_user/2, add_user/5 and add_user/6 adds a user to the user - database. If the operation is successful, this function returns - true. If an error occurs, {error,Reason} is returned. When add_user/2 - is called the Password, UserData Port and Dir options is mandatory.

+

add_user/2, add_user/5 and add_user/6 adds a + user to the user + database. If the operation is successful, this function returns + true. If an error occurs, {error,Reason} is returned. + When add_user/2 is called the Password, + UserData Port and Dir options is mandatory.

+ +
+ delete_user(UserName,Options) -> true | {error, Reason} delete_user(UserName, Port, Dir) -> true | {error, Reason} @@ -79,13 +87,16 @@

delete_user/2, delete_user/3 and delete_user/4 - deletes a user - from the user database. If the operation is successful, this - function returns true. If an error occurs, - {error,Reason} is returned. When delete_user/2 is - called the Port and Dir options are mandatory.

+ deletes a user from the user database. + If the operation is successful, this function returns true. + If an error occurs, {error,Reason} is returned. + When delete_user/2 is called the Port and Dir options + are mandatory.

+ +
+ get_user(UserName,Options) -> {ok, #httpd_user} |{error, Reason} get_user(UserName, Port, Dir) -> {ok, #httpd_user} | {error, Reason} @@ -104,12 +115,15 @@

get_user/2, get_user/3 and get_user/4 returns a - httpd_user record containing the userdata for a - specific user. If the user cannot be found, {error, Reason} - is returned. When get_user/2 is called the Port and Dir - options are mandatory.

+ httpd_user record containing the userdata for a + specific user. If the user cannot be found, {error, Reason} + is returned. When get_user/2 is called the Port and Dir + options are mandatory.

+ +
+ list_users(Options) -> {ok, Users} | {error, Reason} list_users(Port, Dir) -> {ok, Users} | {error, Reason} @@ -127,12 +141,16 @@ -

list_users/1, list_users/2 and list_users/3 returns a list - of users in the user database for a specific Port/Dir. - When list_users/1 is called the Port and Dir - options are mandatory.

+

list_users/1, list_users/2 and list_users/3 + returns a list + of users in the user database for a specific Port/Dir. + When list_users/1 is called the Port and Dir + options are mandatory.

+ +
+ add_group_member(GroupName, UserName, Options) -> true | {error, Reason} add_group_member(GroupName, UserName, Port, Dir) -> true | {error, Reason} @@ -151,13 +169,18 @@ -

add_group_member/3, add_group_member/4 and add_group_member/5 - adds a user to a group. If the group does not exist, it - is created and the user is added to the group. Upon successful - operation, this function returns true. When add_group_members/3 - is called the Port and Dir options are mandatory.

+

add_group_member/3, add_group_member/4 and + add_group_member/5 + adds a user to a group. If the group does not exist, it + is created and the user is added to the group. Upon successful + operation, this function returns true. + When add_group_members/3 + is called the Port and Dir options are mandatory.

+ +
+ delete_group_member(GroupName, UserName, Options) -> true | {error, Reason} delete_group_member(GroupName, UserName, Port, Dir) -> true | {error, Reason} @@ -176,13 +199,17 @@ -

delete_group_member/3, delete_group_member/4 and delete_group_member/5 deletes a user from a group. - If the group or the user does not exist, - this function returns an error, otherwise it returns true. - When delete_group_member/3 is called the Port and Dir options - are mandatory.

+

delete_group_member/3, delete_group_member/4 and + delete_group_member/5 deletes a user from a group. + If the group or the user does not exist, + this function returns an error, otherwise it returns true. + When delete_group_member/3 is called the Port and Dir options + are mandatory.

+ +
+ list_group_members(GroupName, Options) -> {ok, Users} | {error, Reason} list_group_members(GroupName, Port, Dir) -> {ok, Users} | {error, Reason} @@ -201,13 +228,17 @@ -

list_group_members/2, list_group_members/3 and list_group_members/4 - lists the members of a specified group. If the group does not - exist or there is an error, {error, Reason} is returned. - When list_group_members/2 is called the Port and Dir options - are mandatory.

+

list_group_members/2, list_group_members/3 and + list_group_members/4 + lists the members of a specified group. If the group does not + exist or there is an error, {error, Reason} is returned. + When list_group_members/2 is called the Port and Dir options + are mandatory.

+ +
+ list_groups(Options) -> {ok, Groups} | {error, Reason} list_groups(Port, Dir) -> {ok, Groups} | {error, Reason} @@ -225,12 +256,16 @@ -

list_groups/1, list_groups/2 and list_groups/3 lists all - the groups available. If there is an error, {error, Reason} - is returned. When list_groups/1 is called the Port and Dir options - are mandatory.

+

list_groups/1, list_groups/2 and list_groups/3 + lists all the groups available. + If there is an error, {error, Reason} is returned. + When list_groups/1 is called the Port and Dir options + are mandatory.

+ +
+ delete_group(GroupName, Options) -> true | {error,Reason} <name>delete_group(GroupName, Port, Dir) -> true | {error, Reason} delete_group(GroupName, Address, Port, Dir) -> true | {error, Reason} @@ -247,12 +282,16 @@ -

delete_group/2, delete_group/3 and delete_group/4 deletes the - group specified and returns true. If there is an error, - {error, Reason} is returned. When delete_group/2 is called the - Port and Dir options are mandatory.

+

delete_group/2, delete_group/3 and delete_group/4 + deletes the group specified and returns true. + If there is an error, {error, Reason} is returned. + When delete_group/2 is called the + Port and Dir options are mandatory.

+ +
+ update_password(Port, Dir, OldPassword, NewPassword, NewPassword) -> ok | {error, Reason} update_password(Address,Port, Dir, OldPassword, NewPassword, NewPassword) -> ok | {error, Reason} @@ -268,10 +307,12 @@ -

update_password/5 and update_password/6 Updates the AuthAccessPassword - for the specified directory. If NewPassword is equal to "NoPassword" no password is requires to - change authorisation data. If NewPassword is equal to "DummyPassword" no changes can be done - without changing the password first.

+

update_password/5 and update_password/6 + Updates the AuthAccessPassword for the specified directory. + If NewPassword is equal to "NoPassword" no password is requires to + change authorisation data. + If NewPassword is equal to "DummyPassword" no changes can be done + without changing the password first.

diff --git a/lib/inets/doc/src/notes_history.xml b/lib/inets/doc/src/notes_history.xml index 151bec375e..bd59c1ba47 100644 --- a/lib/inets/doc/src/notes_history.xml +++ b/lib/inets/doc/src/notes_history.xml @@ -1,10 +1,10 @@ - +
- 20042011 + 20042012 Ericsson AB. All Rights Reserved. diff --git a/lib/inets/doc/src/part.xml b/lib/inets/doc/src/part.xml index 36955df6b3..3b6734a9b8 100644 --- a/lib/inets/doc/src/part.xml +++ b/lib/inets/doc/src/part.xml @@ -1,10 +1,10 @@ - +
- 20042009 + 20042012 Ericsson AB. All Rights Reserved. diff --git a/lib/inets/doc/src/part_notes.xml b/lib/inets/doc/src/part_notes.xml index 21f464318b..81b0dedbfa 100644 --- a/lib/inets/doc/src/part_notes.xml +++ b/lib/inets/doc/src/part_notes.xml @@ -1,10 +1,10 @@ - +
- 20022009 + 20022012 Ericsson AB. All Rights Reserved. diff --git a/lib/inets/doc/src/part_notes_history.xml b/lib/inets/doc/src/part_notes_history.xml index 3c1e6f5232..f714a6d2e3 100644 --- a/lib/inets/doc/src/part_notes_history.xml +++ b/lib/inets/doc/src/part_notes_history.xml @@ -1,10 +1,10 @@ - +
- 20042009 + 20042012 Ericsson AB. All Rights Reserved. diff --git a/lib/inets/doc/src/tftp.xml b/lib/inets/doc/src/tftp.xml index 96d6ae0dd5..0b3e93a153 100644 --- a/lib/inets/doc/src/tftp.xml +++ b/lib/inets/doc/src/tftp.xml @@ -1,10 +1,10 @@ - +
- 20062009 + 20062012 Ericsson AB. All Rights Reserved. @@ -218,6 +218,8 @@ 5 times when the timeout expires.

+ + @@ -231,11 +233,14 @@

Starts a daemon process which listens for udp packets on a - port. When it receives a request for read or write it spawns - a temporary server process which handles the actual transfer - of the (virtual) file.

+ port. When it receives a request for read or write it spawns + a temporary server process which handles the actual transfer + of the (virtual) file.

+ +
+ read_file(RemoteFilename, LocalFilename, Options) -> {ok, LastCallbackState} | {error, Reason} Read a (virtual) file from a TFTP server @@ -248,23 +253,26 @@

Reads a (virtual) file RemoteFilename from a TFTP - server.

-

If LocalFilename is the atom binary, - tftp_binary is used as callback module. It concatenates - all transferred blocks and returns them as one single binary - in LastCallbackState.

-

If LocalFilename is a string and there are no - registered callback modules, tftp_file is used as - callback module. It writes each transferred block to the file - named LocalFilename and returns the number of - transferred bytes in LastCallbackState.

-

If LocalFilename is a string and there are registered - callback modules, LocalFilename is tested against - the regexps of these and the callback module corresponding to - the first match is used, or an error tuple is returned if no - matching regexp is found.

+ server.

+

If LocalFilename is the atom binary, + tftp_binary is used as callback module. It concatenates + all transferred blocks and returns them as one single binary + in LastCallbackState.

+

If LocalFilename is a string and there are no + registered callback modules, tftp_file is used as + callback module. It writes each transferred block to the file + named LocalFilename and returns the number of + transferred bytes in LastCallbackState.

+

If LocalFilename is a string and there are registered + callback modules, LocalFilename is tested against + the regexps of these and the callback module corresponding to + the first match is used, or an error tuple is returned if no + matching regexp is found.

+ +
+ write_file(RemoteFilename, LocalFilename, Options) -> {ok, LastCallbackState} | {error, Reason} Write a (virtual) file to a TFTP server @@ -288,10 +296,12 @@ block by block and returns the number of transferred bytes in LastCallbackState.

If LocalFilename is a string and there are registered - callback modules, LocalFilename is tested against - the regexps of these and the callback module corresponding to - the first match is used, or an error tuple is returned if no - matching regexp is found.

+ callback modules, LocalFilename is tested against + the regexps of these and the callback module corresponding to + the first match is used, or an error tuple is returned if no + matching regexp is found.

+ +
@@ -304,8 +314,9 @@ Reason = term() -

Returns info about all TFTP daemon processes. -

+

Returns info about all TFTP daemon processes.

+ +
@@ -318,8 +329,9 @@ Reason = term() -

Returns info about all TFTP server processes. -

+

Returns info about all TFTP server processes.

+ +
@@ -332,6 +344,8 @@

Returns info about a TFTP daemon, server or client process.

+ +
@@ -346,8 +360,9 @@ Reason = term() -

Changes config for all TFTP daemon processes -

+

Changes config for all TFTP daemon processes.

+ +
@@ -362,8 +377,9 @@ Reason = term() -

Changes config for all TFTP server processes -

+

Changes config for all TFTP server processes.

+ +
@@ -378,8 +394,11 @@

Changes config for a TFTP daemon, server or client process

+ +
+ start() -> ok | {error, Reason} Start the Inets application @@ -442,8 +461,9 @@ by the already ongoing connection on the server side. By not setting up yet another connection, in parallel with the ongoing one, the server will - consumer lesser resources. -

+ consumer lesser resources.

+ + @@ -468,17 +488,20 @@ Text = string() -

Prepares to open a file on the client side.

-

No new options may be added, but the ones that are present in - SuggestedOptions may be omitted or replaced with new - values in AcceptedOptions.

-

Will be followed by a call to open/4 before any - read/write access is performed. AcceptedOptions is - sent to the server which replies with those options that it - accepts. These will be forwarded to open/4 as - SuggestedOptions.

+

Prepares to open a file on the client side.

+

No new options may be added, but the ones that are present in + SuggestedOptions may be omitted or replaced with new + values in AcceptedOptions.

+

Will be followed by a call to open/4 before any + read/write access is performed. AcceptedOptions is + sent to the server which replies with those options that it + accepts. These will be forwarded to open/4 as + SuggestedOptions.

+ +
+ open(Peer, Access, Filename, Mode, SuggestedOptions, State) -> {ok, AcceptedOptions, NewState} | {error, {Code, Text}} Open a file for read or write access @@ -503,14 +526,17 @@

Opens a file for read or write access.

On the client side where the open/5 call has been - preceded by a call to prepare/5, all options must be - accepted or rejected.

-

On the server side, where there is no preceding - prepare/5 call, no new options may be added, but - the ones that are present in SuggestedOptions may be - omitted or replaced with new values in AcceptedOptions.

+ preceded by a call to prepare/5, all options must be + accepted or rejected.

+

On the server side, where there is no preceding + prepare/5 call, no new options may be added, but + the ones that are present in SuggestedOptions may be + omitted or replaced with new values in AcceptedOptions.

+ +
+ read(State) -> {more, Bin, NewState} | {last, Bin, FileSize} | {error, {Code, Text}} Read a chunk from the file @@ -526,15 +552,18 @@

Read a chunk from the file.

The callback function is expected to close - the file when the last file chunk is - encountered. When an error is encountered - the callback function is expected to clean - up after the aborted file transfer, such as - closing open file descriptors etc. In both - cases there will be no more calls to any of - the callback functions.

+ the file when the last file chunk is + encountered. When an error is encountered + the callback function is expected to clean + up after the aborted file transfer, such as + closing open file descriptors etc. In both + cases there will be no more calls to any of + the callback functions.

+ +
+ write(Bin, State) -> {more, NewState} | {last, FileSize} | {error, {Code, Text}} Write a chunk to the file @@ -550,15 +579,18 @@

Write a chunk to the file.

The callback function is expected to close - the file when the last file chunk is - encountered. When an error is encountered - the callback function is expected to clean - up after the aborted file transfer, such as - closing open file descriptors etc. In both - cases there will be no more calls to any of - the callback functions.

+ the file when the last file chunk is + encountered. When an error is encountered + the callback function is expected to clean + up after the aborted file transfer, such as + closing open file descriptors etc. In both + cases there will be no more calls to any of + the callback functions.

+ +
+ abort(Code, Text, State) -> ok Abort the file transfer @@ -572,14 +604,14 @@

Invoked when the file transfer is aborted.

The callback function is expected to clean - up its used resources after the aborted file - transfer, such as closing open file - descriptors etc. The function will not be - invoked if any of the other callback - functions returns an error, as it is - expected that they already have cleaned up - the necessary resources. It will however be - invoked if the functions fails (crashes).

+ up its used resources after the aborted file + transfer, such as closing open file + descriptors etc. The function will not be + invoked if any of the other callback + functions returns an error, as it is + expected that they already have cleaned up + the necessary resources. It will however be + invoked if the functions fails (crashes).

@@ -589,7 +621,9 @@ LOGGER FUNCTIONS

A tftp_logger callback module should be implemented as a - tftp_logger behavior and export the functions listed below.

+ tftp_logger behavior and export the functions listed below.

+ + @@ -602,7 +636,10 @@ Reason = term() -

Log an error message. See error_logger:error_msg/2 for details.

+

Log an error message. + See error_logger:error_msg/2 for details.

+ +
@@ -615,7 +652,10 @@ Reason = term() -

Log a warning message. See error_logger:warning_msg/2 for details.

+

Log a warning message. + See error_logger:warning_msg/2 for details.

+ +
@@ -628,7 +668,8 @@ Reason = term() -

Log an info message. See error_logger:info_msg/2 for details.

+

Log an info message. + See error_logger:info_msg/2 for details.

-- cgit v1.2.3 From 48d888e192b243964d80a7717789458d38107cf6 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 15 Mar 2012 12:58:57 +0100 Subject: [inets] Updated appup file OTP-9983 --- lib/inets/src/inets_app/inets.appup.src | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index 9dfa16b405..c7029f7b31 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -20,8 +20,12 @@ [ {"5.8.1", [ - {load_module, httpc, soft_purge, soft_purge, [httpc_manager]}, - {update, httpc_manager, soft, soft_purge, soft_purge, []}, + {load_module, http_uri, soft_purge, soft_purge, []}, + {load_module, httpc_response, soft_purge, soft_purge, [http_uri]}, + + {load_module, httpc, soft_purge, soft_purge, + [http_uri, httpc_manager]}, + {update, httpc_manager, soft, soft_purge, soft_purge, [http_uri]}, {load_module, inets_app, soft_purge, soft_purge, [inets_sup]}, {update, inets_sup, soft, soft_purge, soft_purge, []}, @@ -38,7 +42,11 @@ }, {"5.8", [ - {load_module, httpc, soft_purge, soft_purge, [httpc_manager]}, + {load_module, http_uri, soft_purge, soft_purge, []}, + {load_module, httpc_response, soft_purge, soft_purge, [http_uri]}, + + {load_module, httpc, soft_purge, soft_purge, + [http_uri, httpc_manager]}, {load_module, inets_app, soft_purge, soft_purge, [inets_sup]}, {update, inets_sup, soft, soft_purge, soft_purge, []}, @@ -53,7 +61,7 @@ {update, httpc_handler, {advanced, upgrade_from_pre_5_8_1}, soft_purge, soft_purge, []}, {update, httpc_manager, {advanced, upgrade_from_pre_5_8_1}, - soft_purge, soft_purge, [httpc_handler]}, + soft_purge, soft_purge, [http_uri, httpc_handler]}, {update, httpd_sup, soft, soft_purge, soft_purge, []}, {add_module, inets_trace} @@ -68,8 +76,12 @@ [ {"5.8.1", [ - {load_module, httpc, soft_purge, soft_purge, [httpc_manager]}, - {update, httpc_manager, soft, soft_purge, soft_purge, []}, + {load_module, http_uri, soft_purge, soft_purge, []}, + {load_module, httpc_response, soft_purge, soft_purge, [http_uri]}, + + {load_module, httpc, soft_purge, soft_purge, + [http_uri, httpc_manager]}, + {update, httpc_manager, soft, soft_purge, soft_purge, [http_uri]}, {load_module, inets_app, soft_purge, soft_purge, [inets_sup]}, {update, inets_sup, soft, soft_purge, soft_purge, []}, @@ -86,7 +98,11 @@ }, {"5.8", [ - {load_module, httpc, soft_purge, soft_purge, [httpc_manager]}, + {load_module, http_uri, soft_purge, soft_purge, []}, + {load_module, httpc_response, soft_purge, soft_purge, [http_uri]}, + + {load_module, httpc, soft_purge, soft_purge, + [http_uri, httpc_manager]}, {load_module, inets_app, soft_purge, soft_purge, [inets_sup]}, {update, inets_sup, soft, soft_purge, soft_purge, []}, @@ -101,7 +117,7 @@ {update, httpc_handler, {advanced, upgrade_from_pre_5_8_1}, soft_purge, soft_purge, []}, {update, httpc_manager, {advanced, upgrade_from_pre_5_8_1}, - soft_purge, soft_purge, [httpc_handler]}, + soft_purge, soft_purge, [http_uri, httpc_handler]}, {update, httpd_sup, soft, soft_purge, soft_purge, []}, {remove, {inets_trace, soft_purge, brutal_purge}} -- cgit v1.2.3