30 seconds for receiving the request body:
<example>
- RequestTimeout headerinit=10 bodyinit=30
+ RequestReadTimeout header=10 body=30
</example>
</li>
<li>
- Allow at least 10 seconds to receive the request including the headers.
+ Allow at least 10 seconds to receive the request body.
If the client sends data, increase the timeout by 1 second for every
- 500 bytes received. But do not allow more than 30 seconds for the
- request including the headers:
+ 1000 bytes received, with no upper limit for the timeout (exept for
+ the limit given indirectly by
+ <directive module="core">LimitRequestBody</directive>):
<example>
- RequestTimeout headerinit=10 headerminrate=500 headermax=30
+ RequestReadTimeout body=10,MinRate=1000
</example>
</li>
<li>
- Allow at least 10 seconds to receive the request body.
+ Allow at least 10 seconds to receive the request including the headers.
If the client sends data, increase the timeout by 1 second for every
- 1000 bytes received, with no upper limit for the timeout (exept for
- the limit given indirectly by
- <directive module="core">LimitRequestBody</directive>):
+ 500 bytes received. But do not allow more than 30 seconds for the
+ request including the headers:
<example>
- RequestTimeout bodyinit=10 bodyminrate=1000
+ RequestReadTimeout header=10-30,MinRate=500
</example>
</li>
</section>
<directivesynopsis>
-<name>RequestTimeout</name>
+<name>RequestReadTimeout</name>
<description>Set timeout values for receiving request headers and body from client.
</description>
-<syntax>RequestTimeout
-[headerinit=<var>time</var>
-[headerminrate=<var>rate</var> [headermax=<var>time</var>]]]
-[bodyinit=<var>time</var>
-[bodyminrate=<var>rate</var> [bodymax=<var>time</var>]]]
+<syntax>RequestReadTimeout
+[header=<var>timeout</var>[[-<var>maxtimeout</var>],MinRate=<var>rate</var>]
+[body=<var>timeout</var>[[-<var>maxtimeout</var>],MinRate=<var>rate</var>]
</syntax>
-<default>Unset; all values 0</default>
+<default>Unset; no limit</default>
<contextlist><context>server config</context><context>virtual host</context>
</contextlist>
(usually the case on Linux and FreeBSD), the socket is not sent to the
server process before at least one byte (or the whole request for
<code>httpready</code>) is received. The header timeout configured with
- <code>RequestTimeout</code> is only effective after the server process has
+ <code>RequestReadTimeout</code> is only effective after the server process has
received the socket.</p>
- <p>For the timeout parameters, the value 0 means no limit.</p>
+ <p>For each of the two timeout types (header or body), there are three ways
+ to specify the timeout:
+ </p>
+
+ <ul>
- <dl>
+ <li><strong>Fixed timeout value</strong>:<br />
- <dt><code>headerinit</code></dt>
- <dd>The initial timeout for receiving the request headers in seconds.
- Also the timeout for receiving the first byte of the request. If
- <code>headerminrate</code> is not set, the request line and all headers
- must be received within this time.</dd>
+ <example><var>type</var>=<var>timeout</var></example>
- <dt><code>headerminrate</code></dt>
- <dd>The minimum data rate for receiving the request headers in
- bytes/second. Whenever data is received, the timeout is increased
- according to this data rate.</dd>
+ <p>The time in seconds allowed for reading all of the request headers or
+ body, respectively. A value of 0 means no limit.</p>
+ </li>
- <dt><code>headermax</code></dt>
- <dd>The maximum timeout for receiving the request headers in seconds.
- The timeout cannot be increased above this value by
- <code>headerminrate</code>.</dd>
+ <li><strong>Timeout value that is increased when data is
+ received</strong>:<br />
+ <example>
+ <var>type</var>=<var>timeout</var>,MinRate=<var>data_rate</var>
+ </example>
- <dt><code>bodyinit</code></dt>
- <dd>The initial timeout for receiving the request body in seconds.
- Also the timeout for receiving the first byte of the request body. If
- <code>bodyminrate</code> is not set, the complete request body must be
- received within this time.</dd>
+ <p>Same as above, but whenever data is received, the timeout value is
+ increased according to the specified minimum data rate (in bytes per
+ second).</p>
+ </li>
- <dt><code>bodyminrate</code></dt>
- <dd>The minimum data rate for receiving the request body in
- bytes/second. Whenever data is received, the timeout is increased
- according to this data rate.</dd>
+ <li><strong>Timeout value that is increased when data is received, with an
+ upper bound</strong>:<br />
+ <example>
+ <var>type</var>=<var>timeout</var>-<var>maxtimeout</var>,MinRate=<var>data_rate</var>
+ </example>
- <dt><code>bodymax</code></dt>
- <dd>The maximum timeout for receiving the request body in seconds.
- The timeout cannot be increased above this value by
- <code>bodyminrate</code></dd>
+ <p>Same as above, but the timeout will not be increased above the second
+ value of the specified timeout range.</p>
+ </li>
- </dl>
+ </ul>
</usage>
return cfg;
}
-static const char *parse_int(const char *arg, int *val) {
+static const char *parse_int(apr_pool_t *p, const char *arg, int *val) {
char *endptr;
*val = strtol(arg, &endptr, 10);
-
- if ((arg == endptr) || (*endptr != '\0')) {
- return "Value not numerical";
+
+ if (arg == endptr) {
+ return apr_psprintf(p, "Value '%s' not numerical", endptr);
+ }
+ if (*endptr != '\0') {
+ return apr_psprintf(p, "Cannot parse '%s'", endptr);
}
if (*val < 0) {
return "Value must be non-negative";
const char *val)
{
const char *ret = NULL;
- if (!strcasecmp(key, "headerinit")) {
- ret = parse_int(val, &conf->header_timeout);
+ char *rate_str = NULL, *initial_str, *max_str = NULL;
+ int rate = 0, initial = 0, max = 0;
+ enum { PARAM_HEADER, PARAM_BODY } type;
+
+ if (!strcasecmp(key, "header")) {
+ type = PARAM_HEADER;
}
- else if (!strcasecmp(key, "headermax")) {
- ret = parse_int(val, &conf->header_max_timeout);
- if (!ret && conf->header_max_timeout > 0 &&
- conf->header_max_timeout <= conf->header_timeout) {
- ret = "Max timeout must be larger than initial timeout";
- }
+ else if (!strcasecmp(key, "body")) {
+ type = PARAM_BODY;
}
- else if (!strcasecmp(key, "bodyinit")) {
- ret = parse_int(val, &conf->body_timeout);
+ else {
+ return "Unknown RequestReadTimeout parameter";
}
- else if (!strcasecmp(key, "bodymax")) {
- ret = parse_int(val, &conf->body_max_timeout);
- if (!ret && conf->body_max_timeout > 0 &&
- conf->body_max_timeout <= conf->body_timeout) {
- ret = "Max timeout must be larger than initial timeout";
+
+ if ((rate_str = strcasestr(val, ",minrate="))) {
+ initial_str = apr_pstrndup(p, val, rate_str - val);
+ rate_str += strlen(",minrate=");
+ ret = parse_int(p, rate_str, &rate);
+ if (ret)
+ return ret;
+
+ if (rate == 0)
+ return "Minimum data rate must be larger than 0";
+
+ if ((max_str = strchr(initial_str, '-'))) {
+ *max_str++ = '\0';
+ ret = parse_int(p, max_str, &max);
+ if (ret)
+ return ret;
}
+
+ ret = parse_int(p, initial_str, &initial);
}
- else if (!strcasecmp(key, "headerminrate")) {
- ret = parse_int(val, &conf->header_min_rate);
- if (!ret && conf->header_min_rate > 0) {
- conf->header_rate_factor = apr_time_from_sec(1) / conf->header_min_rate;
- }
+ else {
+ if (ap_strchr_c(val, '-'))
+ return "Must set MinRate option if using timeout range";
+ ret = parse_int(p, val, &initial);
}
- else if (!strcasecmp(key, "bodyminrate")) {
- ret = parse_int(val, &conf->body_min_rate);
- if (!ret && conf->body_min_rate > 0) {
- conf->body_rate_factor = apr_time_from_sec(1) / conf->body_min_rate;
- }
+
+ if (ret)
+ return ret;
+
+ if (max && initial >= max) {
+ return "Maximum timeout must be larger than initial timeout";
+ }
+
+ if (type == PARAM_HEADER) {
+ conf->header_timeout = initial;
+ conf->header_max_timeout = max;
+ conf->header_min_rate = rate;
+ if (rate)
+ conf->header_rate_factor = apr_time_from_sec(1) / rate;
}
else {
- ret = "unknown RequestTimeout parameter";
+ conf->body_timeout = initial;
+ conf->body_max_timeout = max;
+ conf->body_min_rate = rate;
+ if (rate)
+ conf->body_rate_factor = apr_time_from_sec(1) / rate;
}
return ret;
-
}
static const char *set_reqtimeouts(cmd_parms *cmd, void *mconfig,
word = ap_getword_conf(cmd->pool, &arg);
val = strchr(word, '=');
if (!val) {
- return "Invalid RequestTimeout parameter. Parameter must be "
+ return "Invalid RequestReadTimeout parameter. Parameter must be "
"in the form 'key=value'";
}
else
err = set_reqtimeout_param(conf, cmd->pool, word, val);
if (err)
- return apr_pstrcat(cmd->temp_pool, "RequestTimeout: ", err, " ",
- word, "=", val, "; ", NULL);
+ return apr_psprintf(cmd->temp_pool, "RequestReadTimeout: %s=%s: %s",
+ word, val, err);
}
return NULL;
}
static const command_rec reqtimeout_cmds[] = {
- AP_INIT_RAW_ARGS("RequestTimeout", set_reqtimeouts, NULL, RSRC_CONF,
- "Adjust various Request Timeout parameters"),
+ AP_INIT_RAW_ARGS("RequestReadTimeout", set_reqtimeouts, NULL, RSRC_CONF,
+ "Set various timeout parameters for reading request "
+ "headers and body"),
{NULL}
};