--- modules/filters/mod_reqtimeout.c (revision 1703807) +++ modules/filters/mod_reqtimeout.c (working copy) @@ -48,6 +48,14 @@ apr_time_t body_rate_factor; } reqtimeout_srv_cfg; +typedef struct +{ + int body_timeout; /* timeout for reading the req body in secs */ + int body_max_timeout; /* max timeout for req body in secs */ + int body_min_rate; /* min rate for reading req body in bytes/s */ + apr_time_t body_rate_factor; +} reqtimeout_dir_cfg; + /* this struct is used both as conn_config and as filter context */ typedef struct { @@ -417,6 +425,8 @@ reqtimeout_srv_cfg *cfg; reqtimeout_con_cfg *ccfg = ap_get_module_config(r->connection->conn_config, &reqtimeout_module); + reqtimeout_dir_cfg *dcfg = + ap_get_module_config(r->per_dir_config, &reqtimeout_module); if (ccfg == NULL || r->method_number == M_CONNECT) { /* either disabled for this connection or a CONNECT request */ @@ -429,7 +439,14 @@ ccfg->timeout_at = 0; ccfg->max_timeout_at = 0; ccfg->type = "body"; - if (cfg->body_timeout != UNSET) { + + if (dcfg->body_timeout != UNSET) { + ccfg->new_timeout = dcfg->body_timeout; + ccfg->new_max_timeout = dcfg->body_max_timeout; + ccfg->min_rate = dcfg->body_min_rate; + ccfg->rate_factor = dcfg->body_rate_factor; + } + else 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; @@ -479,6 +496,33 @@ return cfg; } +static void *reqtimeout_create_dir_config(apr_pool_t *p, char *dir) +{ + reqtimeout_dir_cfg *dcfg = apr_pcalloc(p, sizeof(reqtimeout_dir_cfg)); + + dcfg->body_timeout = UNSET; + dcfg->body_max_timeout = UNSET; + dcfg->body_min_rate = UNSET; + + return dcfg; +} + +static void *reqtimeout_merge_dir_config(apr_pool_t *p, void *base_, void *add_) +{ + reqtimeout_dir_cfg *base = base_; + reqtimeout_dir_cfg *add = add_; + reqtimeout_dir_cfg *dcfg = apr_pcalloc(p, sizeof(reqtimeout_dir_cfg)); + + MERGE_INT(dcfg, base, add, body_timeout); + MERGE_INT(dcfg, base, add, body_max_timeout); + MERGE_INT(dcfg, base, add, body_min_rate); + + dcfg->body_rate_factor = (dcfg->body_min_rate == UNSET) ? + base->body_rate_factor : add->body_rate_factor; + + return dcfg; +} + static const char *parse_int(apr_pool_t *p, const char *arg, int *val) { char *endptr; *val = strtol(arg, &endptr, 10); @@ -495,30 +539,16 @@ return NULL; } -static const char *set_reqtimeout_param(reqtimeout_srv_cfg *conf, - apr_pool_t *p, - const char *key, - const char *val) +static const char *parse_setting(apr_pool_t *p, const char *val, int *initial, + int *max, int *rate) { const char *ret = NULL; 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, "body")) { - type = PARAM_BODY; - } - else { - return "Unknown RequestReadTimeout parameter"; - } - if ((rate_str = ap_strcasestr(val, ",minrate="))) { initial_str = apr_pstrndup(p, val, rate_str - val); rate_str += strlen(",minrate="); - ret = parse_int(p, rate_str, &rate); + ret = parse_int(p, rate_str, rate); if (ret) return ret; @@ -527,26 +557,52 @@ if ((max_str = strchr(initial_str, '-'))) { *max_str++ = '\0'; - ret = parse_int(p, max_str, &max); + ret = parse_int(p, max_str, max); if (ret) return ret; } - ret = parse_int(p, initial_str, &initial); + ret = parse_int(p, initial_str, initial); } else { if (ap_strchr_c(val, '-')) return "Must set MinRate option if using timeout range"; - ret = parse_int(p, val, &initial); + ret = parse_int(p, val, initial); } if (ret) return ret; - if (max && initial >= max) { + if (*max && *initial >= *max) { return "Maximum timeout must be larger than initial timeout"; } + return NULL; +} + +static const char *set_reqtimeout_srv_param(reqtimeout_srv_cfg *conf, + apr_pool_t *p, + const char *key, + const char *val) +{ + const char *ret = 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, "body")) { + type = PARAM_BODY; + } + else { + return "Unknown RequestReadTimeout parameter"; + } + + ret = parse_setting(p, val, &initial, &max, &rate); + if (ret) + return ret; + if (type == PARAM_HEADER) { conf->header_timeout = initial; conf->header_max_timeout = max; @@ -561,9 +617,38 @@ if (rate) conf->body_rate_factor = apr_time_from_sec(1) / rate; } + return ret; } +static const char *set_reqtimeout_dir_param(reqtimeout_dir_cfg *dcfg, + apr_pool_t *p, + const char *key, + const char *val) +{ + const char *ret = NULL; + int rate = 0, initial = 0, max = 0; + + if (!strcasecmp(key, "header")) { + return "Header timeout can not be changed within a location or directory"; + } + else if (strcasecmp(key, "body")) { + return "Unknown RequestReadTimeout parameter"; + } + + ret = parse_setting(p, val, &initial, &max, &rate); + if (ret) + return ret; + + dcfg->body_timeout = initial; + dcfg->body_max_timeout = max; + dcfg->body_min_rate = rate; + if (rate) + dcfg->body_rate_factor = apr_time_from_sec(1) / rate; + + return ret; +} + static const char *set_reqtimeouts(cmd_parms *cmd, void *mconfig, const char *arg) { @@ -584,7 +669,12 @@ else *val++ = '\0'; - err = set_reqtimeout_param(conf, cmd->pool, word, val); + if (cmd->path == NULL) { + err = set_reqtimeout_srv_param(conf, cmd->pool, word, val); + } + else { + err = set_reqtimeout_dir_param(mconfig, cmd->pool, word, val); + } if (err) return apr_psprintf(cmd->temp_pool, "RequestReadTimeout: %s=%s: %s", @@ -616,7 +706,7 @@ ap_hook_pre_read_request(reqtimeout_before_header, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_post_read_request(reqtimeout_before_body, NULL, NULL, + ap_hook_post_perdir_config(reqtimeout_before_body, NULL, NULL, APR_HOOK_MIDDLE); #if MRT_DEFAULT_HEADER_MIN_RATE > 0 @@ -628,7 +718,7 @@ } static const command_rec reqtimeout_cmds[] = { - AP_INIT_RAW_ARGS("RequestReadTimeout", set_reqtimeouts, NULL, RSRC_CONF, + AP_INIT_RAW_ARGS("RequestReadTimeout", set_reqtimeouts, NULL, ACCESS_CONF|RSRC_CONF, "Set various timeout parameters for reading request " "headers and body"), {NULL} @@ -636,8 +726,8 @@ AP_DECLARE_MODULE(reqtimeout) = { STANDARD20_MODULE_STUFF, - NULL, /* create per-dir config structures */ - NULL, /* merge per-dir config structures */ + reqtimeout_create_dir_config, /* create per-dir config structures */ + reqtimeout_merge_dir_config, /* merge per-dir config structures */ reqtimeout_create_srv_config, /* create per-server config structures */ reqtimeout_merge_srv_config, /* merge per-server config structures */ reqtimeout_cmds, /* table of config file commands */