Lines 38-51
module AP_MODULE_DECLARE_DATA reqtimeout_module;
Link Here
|
38 |
|
38 |
|
39 |
typedef struct |
39 |
typedef struct |
40 |
{ |
40 |
{ |
41 |
int header_timeout; /* timeout for reading the req hdrs in secs */ |
41 |
int timeout; /* timeout in secs */ |
42 |
int header_max_timeout; /* max timeout for req hdrs in secs */ |
42 |
int max_timeout; /* max timeout in secs */ |
43 |
int header_min_rate; /* min rate for reading req hdrs in bytes/s */ |
43 |
int min_rate; /* min rate in bytes/s */ |
44 |
apr_time_t header_rate_factor; |
44 |
apr_time_t rate_factor; |
45 |
int body_timeout; /* timeout for reading the req body in secs */ |
45 |
} reqtimeout_stage_t; |
46 |
int body_max_timeout; /* max timeout for req body in secs */ |
46 |
|
47 |
int body_min_rate; /* min rate for reading req body in bytes/s */ |
47 |
typedef struct |
48 |
apr_time_t body_rate_factor; |
48 |
{ |
|
|
49 |
reqtimeout_stage_t handshake; /* TLS handshake */ |
50 |
reqtimeout_stage_t header; /* Reading the HTTP header */ |
51 |
reqtimeout_stage_t body; /* Reading the body */ |
49 |
} reqtimeout_srv_cfg; |
52 |
} reqtimeout_srv_cfg; |
50 |
|
53 |
|
51 |
/* this struct is used both as conn_config and as filter context */ |
54 |
/* this struct is used both as conn_config and as filter context */ |
Lines 56-61
typedef struct
Link Here
|
56 |
int min_rate; |
59 |
int min_rate; |
57 |
int new_timeout; |
60 |
int new_timeout; |
58 |
int new_max_timeout; |
61 |
int new_max_timeout; |
|
|
62 |
int in_handshake; |
59 |
int in_keep_alive; |
63 |
int in_keep_alive; |
60 |
char *type; |
64 |
char *type; |
61 |
apr_socket_t *socket; |
65 |
apr_socket_t *socket; |
Lines 177-182
static apr_status_t reqtimeout_filter(ap_filter_t
Link Here
|
177 |
apr_interval_time_t saved_sock_timeout = UNSET; |
181 |
apr_interval_time_t saved_sock_timeout = UNSET; |
178 |
reqtimeout_con_cfg *ccfg = f->ctx; |
182 |
reqtimeout_con_cfg *ccfg = f->ctx; |
179 |
|
183 |
|
|
|
184 |
if (ccfg->in_handshake < 0) { |
185 |
return ap_get_brigade(f->next, bb, mode, block, readbytes); |
186 |
} |
187 |
|
180 |
if (ccfg->in_keep_alive) { |
188 |
if (ccfg->in_keep_alive) { |
181 |
/* For this read[_request line()], wait for the first byte using the |
189 |
/* For this read[_request line()], wait for the first byte using the |
182 |
* normal keep-alive timeout (hence don't take this expected idle time |
190 |
* normal keep-alive timeout (hence don't take this expected idle time |
Lines 358-364
static int reqtimeout_init(conn_rec *c)
Link Here
|
358 |
cfg = ap_get_module_config(c->base_server->module_config, |
366 |
cfg = ap_get_module_config(c->base_server->module_config, |
359 |
&reqtimeout_module); |
367 |
&reqtimeout_module); |
360 |
AP_DEBUG_ASSERT(cfg != NULL); |
368 |
AP_DEBUG_ASSERT(cfg != NULL); |
361 |
if (cfg->header_timeout == 0 && cfg->body_timeout == 0) { |
369 |
|
|
|
370 |
if ((cfg->handshake.timeout == 0 || cfg->handshake.timeout == UNSET) |
371 |
&& cfg->header.timeout == 0 && cfg->body.timeout == 0) { |
362 |
/* disabled for this vhost */ |
372 |
/* disabled for this vhost */ |
363 |
return DECLINED; |
373 |
return DECLINED; |
364 |
} |
374 |
} |
Lines 369-374
static int reqtimeout_init(conn_rec *c)
Link Here
|
369 |
ap_set_module_config(c->conn_config, &reqtimeout_module, ccfg); |
379 |
ap_set_module_config(c->conn_config, &reqtimeout_module, ccfg); |
370 |
ap_add_output_filter(reqtimeout_filter_name, ccfg, NULL, c); |
380 |
ap_add_output_filter(reqtimeout_filter_name, ccfg, NULL, c); |
371 |
ap_add_input_filter(reqtimeout_filter_name, ccfg, NULL, c); |
381 |
ap_add_input_filter(reqtimeout_filter_name, ccfg, NULL, c); |
|
|
382 |
if (cfg->handshake.timeout > 0) { |
383 |
ccfg->new_timeout = cfg->handshake.timeout; |
384 |
ccfg->new_max_timeout = cfg->handshake.max_timeout; |
385 |
ccfg->min_rate = cfg->handshake.min_rate; |
386 |
ccfg->rate_factor = cfg->handshake.rate_factor; |
387 |
ccfg->type = "handshake"; |
388 |
ccfg->in_handshake = +1; |
389 |
} |
390 |
else { |
391 |
ccfg->in_handshake = -1; |
392 |
} |
372 |
} |
393 |
} |
373 |
|
394 |
|
374 |
/* we are not handling the connection, we just do initialization */ |
395 |
/* we are not handling the connection, we just do initialization */ |
Lines 396-407
static void reqtimeout_before_header(request_rec *
Link Here
|
396 |
ccfg->timeout_at = 0; |
417 |
ccfg->timeout_at = 0; |
397 |
ccfg->max_timeout_at = 0; |
418 |
ccfg->max_timeout_at = 0; |
398 |
ccfg->in_keep_alive = (c->keepalives > 0); |
419 |
ccfg->in_keep_alive = (c->keepalives > 0); |
|
|
420 |
ccfg->in_handshake = 0; |
399 |
ccfg->type = "header"; |
421 |
ccfg->type = "header"; |
400 |
if (cfg->header_timeout != UNSET) { |
422 |
if (cfg->header.timeout != UNSET) { |
401 |
ccfg->new_timeout = cfg->header_timeout; |
423 |
ccfg->new_timeout = cfg->header.timeout; |
402 |
ccfg->new_max_timeout = cfg->header_max_timeout; |
424 |
ccfg->new_max_timeout = cfg->header.max_timeout; |
403 |
ccfg->min_rate = cfg->header_min_rate; |
425 |
ccfg->min_rate = cfg->header.min_rate; |
404 |
ccfg->rate_factor = cfg->header_rate_factor; |
426 |
ccfg->rate_factor = cfg->header.rate_factor; |
405 |
} |
427 |
} |
406 |
else { |
428 |
else { |
407 |
ccfg->new_timeout = MRT_DEFAULT_HEADER_TIMEOUT; |
429 |
ccfg->new_timeout = MRT_DEFAULT_HEADER_TIMEOUT; |
Lines 432-442
static int reqtimeout_before_body(request_rec *r)
Link Here
|
432 |
/* disabled for a CONNECT request */ |
454 |
/* disabled for a CONNECT request */ |
433 |
ccfg->new_timeout = 0; |
455 |
ccfg->new_timeout = 0; |
434 |
} |
456 |
} |
435 |
else if (cfg->body_timeout != UNSET) { |
457 |
else if (cfg->body.timeout != UNSET) { |
436 |
ccfg->new_timeout = cfg->body_timeout; |
458 |
ccfg->new_timeout = cfg->body.timeout; |
437 |
ccfg->new_max_timeout = cfg->body_max_timeout; |
459 |
ccfg->new_max_timeout = cfg->body.max_timeout; |
438 |
ccfg->min_rate = cfg->body_min_rate; |
460 |
ccfg->min_rate = cfg->body.min_rate; |
439 |
ccfg->rate_factor = cfg->body_rate_factor; |
461 |
ccfg->rate_factor = cfg->body.rate_factor; |
440 |
} |
462 |
} |
441 |
else { |
463 |
else { |
442 |
ccfg->new_timeout = MRT_DEFAULT_BODY_TIMEOUT; |
464 |
ccfg->new_timeout = MRT_DEFAULT_BODY_TIMEOUT; |
Lines 451-462
static void *reqtimeout_create_srv_config(apr_pool
Link Here
|
451 |
{ |
473 |
{ |
452 |
reqtimeout_srv_cfg *cfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg)); |
474 |
reqtimeout_srv_cfg *cfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg)); |
453 |
|
475 |
|
454 |
cfg->header_timeout = UNSET; |
476 |
cfg->handshake.timeout = UNSET; |
455 |
cfg->header_max_timeout = UNSET; |
477 |
cfg->handshake.max_timeout = UNSET; |
456 |
cfg->header_min_rate = UNSET; |
478 |
cfg->handshake.min_rate = UNSET; |
457 |
cfg->body_timeout = UNSET; |
479 |
cfg->header.timeout = UNSET; |
458 |
cfg->body_max_timeout = UNSET; |
480 |
cfg->header.max_timeout = UNSET; |
459 |
cfg->body_min_rate = UNSET; |
481 |
cfg->header.min_rate = UNSET; |
|
|
482 |
cfg->body.timeout = UNSET; |
483 |
cfg->body.max_timeout = UNSET; |
484 |
cfg->body.min_rate = UNSET; |
460 |
|
485 |
|
461 |
return cfg; |
486 |
return cfg; |
462 |
} |
487 |
} |
Lines 468-484
static void *reqtimeout_merge_srv_config(apr_pool_
Link Here
|
468 |
reqtimeout_srv_cfg *add = add_; |
493 |
reqtimeout_srv_cfg *add = add_; |
469 |
reqtimeout_srv_cfg *cfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg)); |
494 |
reqtimeout_srv_cfg *cfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg)); |
470 |
|
495 |
|
471 |
MERGE_INT(cfg, base, add, header_timeout); |
496 |
MERGE_INT(cfg, base, add, handshake.timeout); |
472 |
MERGE_INT(cfg, base, add, header_max_timeout); |
497 |
MERGE_INT(cfg, base, add, handshake.max_timeout); |
473 |
MERGE_INT(cfg, base, add, header_min_rate); |
498 |
MERGE_INT(cfg, base, add, handshake.min_rate); |
474 |
MERGE_INT(cfg, base, add, body_timeout); |
499 |
MERGE_INT(cfg, base, add, header.timeout); |
475 |
MERGE_INT(cfg, base, add, body_max_timeout); |
500 |
MERGE_INT(cfg, base, add, header.max_timeout); |
476 |
MERGE_INT(cfg, base, add, body_min_rate); |
501 |
MERGE_INT(cfg, base, add, header.min_rate); |
|
|
502 |
MERGE_INT(cfg, base, add, body.timeout); |
503 |
MERGE_INT(cfg, base, add, body.max_timeout); |
504 |
MERGE_INT(cfg, base, add, body.min_rate); |
477 |
|
505 |
|
478 |
cfg->header_rate_factor = (cfg->header_min_rate == UNSET) ? |
506 |
cfg->handshake.rate_factor = (cfg->handshake.min_rate == UNSET) |
479 |
base->header_rate_factor : add->header_rate_factor; |
507 |
? base->handshake.rate_factor |
480 |
cfg->body_rate_factor = (cfg->body_min_rate == UNSET) ? |
508 |
: add->handshake.rate_factor; |
481 |
base->body_rate_factor : add->body_rate_factor; |
509 |
cfg->header.rate_factor = (cfg->header.min_rate == UNSET) |
|
|
510 |
? base->header.rate_factor |
511 |
: add->header.rate_factor; |
512 |
cfg->body.rate_factor = (cfg->body.min_rate == UNSET) |
513 |
? base->body.rate_factor |
514 |
: add->body.rate_factor; |
482 |
return cfg; |
515 |
return cfg; |
483 |
} |
516 |
} |
484 |
|
517 |
|
Lines 507-515
static const char *set_reqtimeout_param(reqtimeout
Link Here
|
507 |
const char *ret = NULL; |
540 |
const char *ret = NULL; |
508 |
char *rate_str = NULL, *initial_str, *max_str = NULL; |
541 |
char *rate_str = NULL, *initial_str, *max_str = NULL; |
509 |
int rate = 0, initial = 0, max = 0; |
542 |
int rate = 0, initial = 0, max = 0; |
510 |
enum { PARAM_HEADER, PARAM_BODY } type; |
543 |
enum { PARAM_HANDSHAKE, PARAM_HEADER, PARAM_BODY } type; |
511 |
|
544 |
|
512 |
if (!strcasecmp(key, "header")) { |
545 |
if (!strcasecmp(key, "handshake")) { |
|
|
546 |
type = PARAM_HANDSHAKE; |
547 |
} |
548 |
else if (!strcasecmp(key, "header")) { |
513 |
type = PARAM_HEADER; |
549 |
type = PARAM_HEADER; |
514 |
} |
550 |
} |
515 |
else if (!strcasecmp(key, "body")) { |
551 |
else if (!strcasecmp(key, "body")) { |
Lines 551-571
static const char *set_reqtimeout_param(reqtimeout
Link Here
|
551 |
return "Maximum timeout must be larger than initial timeout"; |
587 |
return "Maximum timeout must be larger than initial timeout"; |
552 |
} |
588 |
} |
553 |
|
589 |
|
554 |
if (type == PARAM_HEADER) { |
590 |
switch (type) { |
555 |
conf->header_timeout = initial; |
591 |
case PARAM_HANDSHAKE: |
556 |
conf->header_max_timeout = max; |
592 |
conf->handshake.timeout = initial; |
557 |
conf->header_min_rate = rate; |
593 |
conf->handshake.max_timeout = max; |
|
|
594 |
conf->handshake.min_rate = rate; |
558 |
if (rate) |
595 |
if (rate) |
559 |
conf->header_rate_factor = apr_time_from_sec(1) / rate; |
596 |
conf->handshake.rate_factor = apr_time_from_sec(1) / rate; |
560 |
} |
597 |
break; |
561 |
else { |
598 |
|
562 |
conf->body_timeout = initial; |
599 |
case PARAM_HEADER: |
563 |
conf->body_max_timeout = max; |
600 |
conf->header.timeout = initial; |
564 |
conf->body_min_rate = rate; |
601 |
conf->header.max_timeout = max; |
|
|
602 |
conf->header.min_rate = rate; |
565 |
if (rate) |
603 |
if (rate) |
566 |
conf->body_rate_factor = apr_time_from_sec(1) / rate; |
604 |
conf->header.rate_factor = apr_time_from_sec(1) / rate; |
|
|
605 |
break; |
606 |
|
607 |
default: |
608 |
conf->body.timeout = initial; |
609 |
conf->body.max_timeout = max; |
610 |
conf->body.min_rate = rate; |
611 |
if (rate) |
612 |
conf->body.rate_factor = apr_time_from_sec(1) / rate; |
613 |
break; |
567 |
} |
614 |
} |
568 |
return ret; |
615 |
return NULL; |
569 |
} |
616 |
} |
570 |
|
617 |
|
571 |
static const char *set_reqtimeouts(cmd_parms *cmd, void *mconfig, |
618 |
static const char *set_reqtimeouts(cmd_parms *cmd, void *mconfig, |
Lines 624-630
static void reqtimeout_hooks(apr_pool_t *pool)
Link Here
|
624 |
* e.g. mod_ftp. Also, if mod_reqtimeout used the pre_connection hook, it |
671 |
* e.g. mod_ftp. Also, if mod_reqtimeout used the pre_connection hook, it |
625 |
* would be inserted on mod_proxy's backend connections. |
672 |
* would be inserted on mod_proxy's backend connections. |
626 |
*/ |
673 |
*/ |
627 |
ap_hook_process_connection(reqtimeout_init, NULL, NULL, APR_HOOK_LAST); |
674 |
ap_hook_process_connection(reqtimeout_init, NULL, NULL, APR_HOOK_FIRST); |
628 |
|
675 |
|
629 |
ap_hook_pre_read_request(reqtimeout_before_header, NULL, NULL, |
676 |
ap_hook_pre_read_request(reqtimeout_before_header, NULL, NULL, |
630 |
APR_HOOK_MIDDLE); |
677 |
APR_HOOK_MIDDLE); |
Lines 641-648
static void reqtimeout_hooks(apr_pool_t *pool)
Link Here
|
641 |
|
688 |
|
642 |
static const command_rec reqtimeout_cmds[] = { |
689 |
static const command_rec reqtimeout_cmds[] = { |
643 |
AP_INIT_RAW_ARGS("RequestReadTimeout", set_reqtimeouts, NULL, RSRC_CONF, |
690 |
AP_INIT_RAW_ARGS("RequestReadTimeout", set_reqtimeouts, NULL, RSRC_CONF, |
644 |
"Set various timeout parameters for reading request " |
691 |
"Set various timeout parameters for TLS handshake or " |
645 |
"headers and body"), |
692 |
"reading request headers and body"), |
646 |
{NULL} |
693 |
{NULL} |
647 |
}; |
694 |
}; |
648 |
|
695 |
|