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(-) (limited to 'lib') 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