Commit 3aba51cf authored by Stefan Fritsch's avatar Stefan Fritsch
Browse files

mod_reqtimeout: Change the default to set some reasonable timeout values if loaded


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1199447 13f79535-47bb-0310-9956-ffa450edef68
parent ef3e0183
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@ Changes with Apache 2.3.15
     core: Fix integer overflow in ap_pregsub. This can be triggered e.g.
     with mod_setenvif via a malicious .htaccess. [Stefan Fritsch]

  *) mod_reqtimeout: Change the default to set some reasonable timeout
     values. [Stefan Fritsch]

  *) core, mod_dav_fs: Change default ETag to be "size mtime", i.e. remove
     the inode. PR 49623. [Stefan Fritsch]

+15 −0
Original line number Diff line number Diff line
@@ -73,3 +73,18 @@ ServerSignature Off
# nameserver.
#
HostnameLookups Off

#
# Set a timeout for how long the client may take to send the request header
# and body.
# The default for the headers is header=20-40,MinRate=500, which means wait
# for the first byte of headers for 20 seconds. If some data arrives,
# increase the timeout corresponding to a data rate of 500 bytes/s, but not
# above 40 seconds.
# The default for the request body is body=20,MinRate=500, which is the same
# but has no upper limit for the timeout.
# To disable, set to header=0 body=0
#
<IfModule reqtimeout_module>
  RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500
</IfModule>
+13 −4
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@
<status>Extension</status>
<sourcefile>mod_reqtimeout.c</sourcefile>
<identifier>reqtimeout_module</identifier>
<compatibility>Available in Apache 2.2.15 and later</compatibility>
<compatibility>Available in Apache HTTPD 2.2.15 and later</compatibility>

<section id="examples"><title>Examples</title>

@@ -83,12 +83,14 @@
<description>Set timeout values for receiving request headers and body from client.
</description>
<syntax>RequestReadTimeout
[header=<var>timeout</var>[[-<var>maxtimeout</var>],MinRate=<var>rate</var>]
[body=<var>timeout</var>[[-<var>maxtimeout</var>],MinRate=<var>rate</var>]
[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; no limit</default>
<default>header=20-40,MinRate=500 body=20,MinRate=500</default>
<contextlist><context>server config</context><context>virtual host</context>
</contextlist>
<compatibility>Available in version 2.2.15 and later; defaulted to disabled in
version 2.3.14 and earlier.</compatibility>

<usage>
    <p>This directive can set various timeouts for receiving the request headers
@@ -126,6 +128,13 @@
    body, respectively. A value of 0 means no limit.</p>
    </li>

    <li><strong>Disable module for a vhost:</strong>:<br />

    <example>header=0 body=0</example>

    <p>This disables <module>mod_reqtimeout</module> completely.</p>
    </li>

    <li><strong>Timeout value that is increased when data is
    received</strong>:<br />
    <example>
+3 −0
Original line number Diff line number Diff line
@@ -269,6 +269,9 @@
        limited to 1MB.
        </li>

        <li><module>mod_reqtimeout</module>: If the module is loaded, it
        will now set some default timeouts.</li>

      </ul>
    </section>
  </section>
+68 −33
Original line number Diff line number Diff line
@@ -28,6 +28,14 @@

module AP_MODULE_DECLARE_DATA reqtimeout_module;

#define UNSET                            -1
#define MRT_DEFAULT_HEADER_TIMEOUT       20
#define MRT_DEFAULT_HEADER_MAX_TIMEOUT   40
#define MRT_DEFAULT_HEADER_MIN_RATE      500
#define MRT_DEFAULT_BODY_TIMEOUT         20
#define MRT_DEFAULT_BODY_MAX_TIMEOUT     0
#define MRT_DEFAULT_BODY_MIN_RATE        500

typedef struct
{
    int header_timeout;     /* timeout for reading the req hdrs in secs */
@@ -56,6 +64,8 @@ typedef struct
} reqtimeout_con_cfg;

static const char *const reqtimeout_filter_name = "reqtimeout";
static int default_header_rate_factor;
static int default_body_rate_factor;

static void extend_timeout(reqtimeout_con_cfg *ccfg, apr_bucket_brigade *bb)
{
@@ -161,7 +171,7 @@ static apr_status_t reqtimeout_filter(ap_filter_t *f,
    apr_time_t time_left;
    apr_time_t now;
    apr_status_t rv;
    apr_interval_time_t saved_sock_timeout = -1;
    apr_interval_time_t saved_sock_timeout = UNSET;
    reqtimeout_con_cfg *ccfg = f->ctx;

    if (ccfg->in_keep_alive) {
@@ -325,17 +335,25 @@ static int reqtimeout_init(conn_rec *c)
    cfg = ap_get_module_config(c->base_server->module_config,
                               &reqtimeout_module);
    AP_DEBUG_ASSERT(cfg != NULL);
    if (cfg->header_timeout <= 0 && cfg->body_timeout <= 0) {
        /* not configured for this vhost */
    if (cfg->header_timeout == 0 && cfg->body_timeout == 0) {
        /* disabled for this vhost */
        return DECLINED;
    }

    ccfg = apr_pcalloc(c->pool, sizeof(reqtimeout_con_cfg));
    ccfg->type = "header";
    if (cfg->header_timeout != UNSET) {
        ccfg->new_timeout     = cfg->header_timeout;
        ccfg->new_max_timeout = cfg->header_max_timeout;
    ccfg->type = "header";
        ccfg->min_rate        = cfg->header_min_rate;
        ccfg->rate_factor     = cfg->header_rate_factor;
    }
    else {
        ccfg->new_timeout     = MRT_DEFAULT_HEADER_TIMEOUT;
        ccfg->new_max_timeout = MRT_DEFAULT_HEADER_MAX_TIMEOUT;
        ccfg->min_rate        = MRT_DEFAULT_HEADER_MIN_RATE;
        ccfg->rate_factor     = default_header_rate_factor;
    }
    ap_set_module_config(c->conn_config, &reqtimeout_module, ccfg);

    ap_add_input_filter("reqtimeout", ccfg, NULL, c);
@@ -349,25 +367,29 @@ static int reqtimeout_after_headers(request_rec *r)
    reqtimeout_con_cfg *ccfg =
        ap_get_module_config(r->connection->conn_config, &reqtimeout_module);

    if (ccfg == NULL) {
        /* not configured for this connection */
    if (ccfg == NULL || r->method_number == M_CONNECT) {
        /* either disabled for this connection or a CONNECT request */
        return OK;
    }

    cfg = ap_get_module_config(r->connection->base_server->module_config,
                               &reqtimeout_module);
    AP_DEBUG_ASSERT(cfg != NULL);

    ccfg->timeout_at = 0;
    ccfg->max_timeout_at = 0;
    if (r->method_number != M_CONNECT) {
    ccfg->type = "body";
    if (cfg->body_timeout != UNSET) {
        ccfg->new_timeout     = cfg->body_timeout;
        ccfg->new_max_timeout = cfg->body_max_timeout;
        ccfg->min_rate        = cfg->body_min_rate;
        ccfg->rate_factor     = cfg->body_rate_factor;
        ccfg->type = "body";
    }

    else {
        ccfg->new_timeout     = MRT_DEFAULT_BODY_TIMEOUT;
        ccfg->new_max_timeout = MRT_DEFAULT_BODY_MAX_TIMEOUT;
        ccfg->min_rate        = MRT_DEFAULT_BODY_MIN_RATE;
        ccfg->rate_factor     = default_body_rate_factor;
    }
    return OK;
}

@@ -389,12 +411,19 @@ static int reqtimeout_after_body(request_rec *r)
    ccfg->timeout_at = 0;
    ccfg->max_timeout_at = 0;
    ccfg->in_keep_alive = 1;
    ccfg->type = "header";
    if (ccfg->new_timeout != UNSET) {
        ccfg->new_timeout     = cfg->header_timeout;
        ccfg->new_max_timeout = cfg->header_max_timeout;
        ccfg->min_rate        = cfg->header_min_rate;
        ccfg->rate_factor     = cfg->header_rate_factor;

    ccfg->type = "header";
    }
    else {
        ccfg->new_timeout     = MRT_DEFAULT_HEADER_TIMEOUT;
        ccfg->new_max_timeout = MRT_DEFAULT_HEADER_MAX_TIMEOUT;
        ccfg->min_rate        = MRT_DEFAULT_HEADER_MIN_RATE;
        ccfg->rate_factor     = default_header_rate_factor;
    }

    return OK;
}
@@ -403,17 +432,17 @@ static void *reqtimeout_create_srv_config(apr_pool_t *p, server_rec *s)
{
    reqtimeout_srv_cfg *cfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg));

    cfg->header_timeout = -1;
    cfg->header_max_timeout = -1;
    cfg->header_min_rate = -1;
    cfg->body_timeout = -1;
    cfg->body_max_timeout = -1;
    cfg->body_min_rate = -1;
    cfg->header_timeout = UNSET;
    cfg->header_max_timeout = UNSET;
    cfg->header_min_rate = UNSET;
    cfg->body_timeout = UNSET;
    cfg->body_max_timeout = UNSET;
    cfg->body_min_rate = UNSET;

    return cfg;
}

#define MERGE_INT(cfg, b, a, val) cfg->val = (a->val == -1) ? b->val : a->val;
#define MERGE_INT(cfg, b, a, val) cfg->val = (a->val == UNSET) ? b->val : a->val;
static void *reqtimeout_merge_srv_config(apr_pool_t *p, void *base_, void *add_)
{
    reqtimeout_srv_cfg *base = base_;
@@ -427,11 +456,10 @@ static void *reqtimeout_merge_srv_config(apr_pool_t *p, void *base_, void *add_)
    MERGE_INT(cfg, base, add, body_max_timeout);
    MERGE_INT(cfg, base, add, body_min_rate);

    cfg->header_rate_factor = (cfg->header_min_rate == -1) ? base->header_rate_factor :
                              add->header_rate_factor;
    cfg->body_rate_factor = (cfg->body_min_rate == -1) ? base->body_rate_factor :
                             add->body_rate_factor;

    cfg->header_rate_factor = (cfg->header_min_rate == UNSET) ?
                              base->header_rate_factor : add->header_rate_factor;
    cfg->body_rate_factor = (cfg->body_min_rate == UNSET) ?
                            base->body_rate_factor : add->body_rate_factor;
    return cfg;
}

@@ -574,6 +602,13 @@ static void reqtimeout_hooks(apr_pool_t *pool)
                              APR_HOOK_MIDDLE);
    ap_hook_log_transaction(reqtimeout_after_body, NULL, NULL,
                            APR_HOOK_MIDDLE);

#if MRT_DEFAULT_HEADER_MIN_RATE > 0
    default_header_rate_factor = apr_time_from_sec(1) / MRT_DEFAULT_HEADER_MIN_RATE;
#endif
#if MRT_DEFAULT_BODY_MIN_RATE > 0
    default_body_rate_factor = apr_time_from_sec(1) / MRT_DEFAULT_BODY_MIN_RATE;
#endif
}

static const command_rec reqtimeout_cmds[] = {