Skip to content

Commit 3aba51c

Browse files
author
Stefan Fritsch
committed
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
1 parent ef3e018 commit 3aba51c

5 files changed

Lines changed: 102 additions & 37 deletions

File tree

CHANGES

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ Changes with Apache 2.3.15
1616
core: Fix integer overflow in ap_pregsub. This can be triggered e.g.
1717
with mod_setenvif via a malicious .htaccess. [Stefan Fritsch]
1818

19+
*) mod_reqtimeout: Change the default to set some reasonable timeout
20+
values. [Stefan Fritsch]
21+
1922
*) core, mod_dav_fs: Change default ETag to be "size mtime", i.e. remove
2023
the inode. PR 49623. [Stefan Fritsch]
2124

docs/conf/extra/httpd-default.conf.in

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,18 @@ ServerSignature Off
7373
# nameserver.
7474
#
7575
HostnameLookups Off
76+
77+
#
78+
# Set a timeout for how long the client may take to send the request header
79+
# and body.
80+
# The default for the headers is header=20-40,MinRate=500, which means wait
81+
# for the first byte of headers for 20 seconds. If some data arrives,
82+
# increase the timeout corresponding to a data rate of 500 bytes/s, but not
83+
# above 40 seconds.
84+
# The default for the request body is body=20,MinRate=500, which is the same
85+
# but has no upper limit for the timeout.
86+
# To disable, set to header=0 body=0
87+
#
88+
<IfModule reqtimeout_module>
89+
RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500
90+
</IfModule>

docs/manual/mod/mod_reqtimeout.xml

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
<status>Extension</status>
2929
<sourcefile>mod_reqtimeout.c</sourcefile>
3030
<identifier>reqtimeout_module</identifier>
31-
<compatibility>Available in Apache 2.2.15 and later</compatibility>
31+
<compatibility>Available in Apache HTTPD 2.2.15 and later</compatibility>
3232

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

@@ -83,12 +83,14 @@
8383
<description>Set timeout values for receiving request headers and body from client.
8484
</description>
8585
<syntax>RequestReadTimeout
86-
[header=<var>timeout</var>[[-<var>maxtimeout</var>],MinRate=<var>rate</var>]
87-
[body=<var>timeout</var>[[-<var>maxtimeout</var>],MinRate=<var>rate</var>]
86+
[header=<var>timeout</var>[-<var>maxtimeout</var>][,MinRate=<var>rate</var>]
87+
[body=<var>timeout</var>[-<var>maxtimeout</var>][,MinRate=<var>rate</var>]
8888
</syntax>
89-
<default>Unset; no limit</default>
89+
<default>header=20-40,MinRate=500 body=20,MinRate=500</default>
9090
<contextlist><context>server config</context><context>virtual host</context>
9191
</contextlist>
92+
<compatibility>Available in version 2.2.15 and later; defaulted to disabled in
93+
version 2.3.14 and earlier.</compatibility>
9294

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

131+
<li><strong>Disable module for a vhost:</strong>:<br />
132+
133+
<example>header=0 body=0</example>
134+
135+
<p>This disables <module>mod_reqtimeout</module> completely.</p>
136+
</li>
137+
129138
<li><strong>Timeout value that is increased when data is
130139
received</strong>:<br />
131140
<example>

docs/manual/upgrading.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,9 @@
269269
limited to 1MB.
270270
</li>
271271

272+
<li><module>mod_reqtimeout</module>: If the module is loaded, it
273+
will now set some default timeouts.</li>
274+
272275
</ul>
273276
</section>
274277
</section>

modules/filters/mod_reqtimeout.c

Lines changed: 68 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@
2828

2929
module AP_MODULE_DECLARE_DATA reqtimeout_module;
3030

31+
#define UNSET -1
32+
#define MRT_DEFAULT_HEADER_TIMEOUT 20
33+
#define MRT_DEFAULT_HEADER_MAX_TIMEOUT 40
34+
#define MRT_DEFAULT_HEADER_MIN_RATE 500
35+
#define MRT_DEFAULT_BODY_TIMEOUT 20
36+
#define MRT_DEFAULT_BODY_MAX_TIMEOUT 0
37+
#define MRT_DEFAULT_BODY_MIN_RATE 500
38+
3139
typedef struct
3240
{
3341
int header_timeout; /* timeout for reading the req hdrs in secs */
@@ -56,6 +64,8 @@ typedef struct
5664
} reqtimeout_con_cfg;
5765

5866
static const char *const reqtimeout_filter_name = "reqtimeout";
67+
static int default_header_rate_factor;
68+
static int default_body_rate_factor;
5969

6070
static void extend_timeout(reqtimeout_con_cfg *ccfg, apr_bucket_brigade *bb)
6171
{
@@ -161,7 +171,7 @@ static apr_status_t reqtimeout_filter(ap_filter_t *f,
161171
apr_time_t time_left;
162172
apr_time_t now;
163173
apr_status_t rv;
164-
apr_interval_time_t saved_sock_timeout = -1;
174+
apr_interval_time_t saved_sock_timeout = UNSET;
165175
reqtimeout_con_cfg *ccfg = f->ctx;
166176

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

333343
ccfg = apr_pcalloc(c->pool, sizeof(reqtimeout_con_cfg));
334-
ccfg->new_timeout = cfg->header_timeout;
335-
ccfg->new_max_timeout = cfg->header_max_timeout;
336344
ccfg->type = "header";
337-
ccfg->min_rate = cfg->header_min_rate;
338-
ccfg->rate_factor = cfg->header_rate_factor;
345+
if (cfg->header_timeout != UNSET) {
346+
ccfg->new_timeout = cfg->header_timeout;
347+
ccfg->new_max_timeout = cfg->header_max_timeout;
348+
ccfg->min_rate = cfg->header_min_rate;
349+
ccfg->rate_factor = cfg->header_rate_factor;
350+
}
351+
else {
352+
ccfg->new_timeout = MRT_DEFAULT_HEADER_TIMEOUT;
353+
ccfg->new_max_timeout = MRT_DEFAULT_HEADER_MAX_TIMEOUT;
354+
ccfg->min_rate = MRT_DEFAULT_HEADER_MIN_RATE;
355+
ccfg->rate_factor = default_header_rate_factor;
356+
}
339357
ap_set_module_config(c->conn_config, &reqtimeout_module, ccfg);
340358

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

352-
if (ccfg == NULL) {
353-
/* not configured for this connection */
370+
if (ccfg == NULL || r->method_number == M_CONNECT) {
371+
/* either disabled for this connection or a CONNECT request */
354372
return OK;
355373
}
356-
357374
cfg = ap_get_module_config(r->connection->base_server->module_config,
358375
&reqtimeout_module);
359376
AP_DEBUG_ASSERT(cfg != NULL);
360377

361378
ccfg->timeout_at = 0;
362379
ccfg->max_timeout_at = 0;
363-
if (r->method_number != M_CONNECT) {
364-
ccfg->new_timeout = cfg->body_timeout;
380+
ccfg->type = "body";
381+
if (cfg->body_timeout != UNSET) {
382+
ccfg->new_timeout = cfg->body_timeout;
365383
ccfg->new_max_timeout = cfg->body_max_timeout;
366-
ccfg->min_rate = cfg->body_min_rate;
367-
ccfg->rate_factor = cfg->body_rate_factor;
368-
ccfg->type = "body";
384+
ccfg->min_rate = cfg->body_min_rate;
385+
ccfg->rate_factor = cfg->body_rate_factor;
386+
}
387+
else {
388+
ccfg->new_timeout = MRT_DEFAULT_BODY_TIMEOUT;
389+
ccfg->new_max_timeout = MRT_DEFAULT_BODY_MAX_TIMEOUT;
390+
ccfg->min_rate = MRT_DEFAULT_BODY_MIN_RATE;
391+
ccfg->rate_factor = default_body_rate_factor;
369392
}
370-
371393
return OK;
372394
}
373395

@@ -389,12 +411,19 @@ static int reqtimeout_after_body(request_rec *r)
389411
ccfg->timeout_at = 0;
390412
ccfg->max_timeout_at = 0;
391413
ccfg->in_keep_alive = 1;
392-
ccfg->new_timeout = cfg->header_timeout;
393-
ccfg->new_max_timeout = cfg->header_max_timeout;
394-
ccfg->min_rate = cfg->header_min_rate;
395-
ccfg->rate_factor = cfg->header_rate_factor;
396-
397414
ccfg->type = "header";
415+
if (ccfg->new_timeout != UNSET) {
416+
ccfg->new_timeout = cfg->header_timeout;
417+
ccfg->new_max_timeout = cfg->header_max_timeout;
418+
ccfg->min_rate = cfg->header_min_rate;
419+
ccfg->rate_factor = cfg->header_rate_factor;
420+
}
421+
else {
422+
ccfg->new_timeout = MRT_DEFAULT_HEADER_TIMEOUT;
423+
ccfg->new_max_timeout = MRT_DEFAULT_HEADER_MAX_TIMEOUT;
424+
ccfg->min_rate = MRT_DEFAULT_HEADER_MIN_RATE;
425+
ccfg->rate_factor = default_header_rate_factor;
426+
}
398427

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

406-
cfg->header_timeout = -1;
407-
cfg->header_max_timeout = -1;
408-
cfg->header_min_rate = -1;
409-
cfg->body_timeout = -1;
410-
cfg->body_max_timeout = -1;
411-
cfg->body_min_rate = -1;
435+
cfg->header_timeout = UNSET;
436+
cfg->header_max_timeout = UNSET;
437+
cfg->header_min_rate = UNSET;
438+
cfg->body_timeout = UNSET;
439+
cfg->body_max_timeout = UNSET;
440+
cfg->body_min_rate = UNSET;
412441

413442
return cfg;
414443
}
415444

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

430-
cfg->header_rate_factor = (cfg->header_min_rate == -1) ? base->header_rate_factor :
431-
add->header_rate_factor;
432-
cfg->body_rate_factor = (cfg->body_min_rate == -1) ? base->body_rate_factor :
433-
add->body_rate_factor;
434-
459+
cfg->header_rate_factor = (cfg->header_min_rate == UNSET) ?
460+
base->header_rate_factor : add->header_rate_factor;
461+
cfg->body_rate_factor = (cfg->body_min_rate == UNSET) ?
462+
base->body_rate_factor : add->body_rate_factor;
435463
return cfg;
436464
}
437465

@@ -574,6 +602,13 @@ static void reqtimeout_hooks(apr_pool_t *pool)
574602
APR_HOOK_MIDDLE);
575603
ap_hook_log_transaction(reqtimeout_after_body, NULL, NULL,
576604
APR_HOOK_MIDDLE);
605+
606+
#if MRT_DEFAULT_HEADER_MIN_RATE > 0
607+
default_header_rate_factor = apr_time_from_sec(1) / MRT_DEFAULT_HEADER_MIN_RATE;
608+
#endif
609+
#if MRT_DEFAULT_BODY_MIN_RATE > 0
610+
default_body_rate_factor = apr_time_from_sec(1) / MRT_DEFAULT_BODY_MIN_RATE;
611+
#endif
577612
}
578613

579614
static const command_rec reqtimeout_cmds[] = {

0 commit comments

Comments
 (0)