mod_reqtimeout.c revision 4e0565f42481dff87062cbfc55a2ecaa36b92e83
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf/* Licensed to the Apache Software Foundation (ASF) under one or more
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * contributor license agreements. See the NOTICE file distributed with
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * this work for additional information regarding copyright ownership.
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * The ASF licenses this file to You under the Apache License, Version 2.0
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * (the "License"); you may not use this file except in compliance with
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * the License. You may obtain a copy of the License at
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * Unless required by applicable law or agreed to in writing, software
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * distributed under the License is distributed on an "AS IS" BASIS,
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * See the License for the specific language governing permissions and
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * limitations under the License.
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsftypedef struct
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf int header_timeout; /* timeout for reading the req hdrs in secs */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf int header_max_timeout; /* max timeout for req hdrs in secs */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf int header_min_rate; /* min rate for reading req hdrs in bytes/s */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf int body_timeout; /* timeout for reading the req body in secs */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf int body_max_timeout; /* max timeout for req body in secs */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf int body_min_rate; /* timeout for reading the req body in secs */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf/* this struct is used both as conn_config and as filter context */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsftypedef struct
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsfstatic const char *const reqtimeout_filter_name = "reqtimeout";
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsfstatic void extend_timeout(reqtimeout_con_cfg *ccfg, apr_bucket_brigade *bb)
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (apr_brigade_length(bb, 0, &len) != APR_SUCCESS || len <= 0)
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf new_timeout_at = ccfg->timeout_at + len * ccfg->rate_factor;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (ccfg->max_timeout_at > 0 && new_timeout_at > ccfg->max_timeout_at) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsfstatic apr_status_t check_time_left(reqtimeout_con_cfg *ccfg,
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsfstatic apr_status_t have_lf_or_eos(apr_bucket_brigade *bb)
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf for ( ; b != APR_BRIGADE_SENTINEL(bb) ; b = APR_BUCKET_PREV(b) ) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf const char *str;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf#define MIN(x,y) ((x) < (y) ? (x) : (y))
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf /* For this read, the normal keep-alive timeout must be used */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf return ap_get_brigade(f->next, bb, mode, block, readbytes);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf /* set new timeout */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->timeout_at = now + apr_time_from_sec(ccfg->new_timeout);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->max_timeout_at = now + apr_time_from_sec(ccfg->new_max_timeout);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf /* no timeout set */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf return ap_get_brigade(f->next, bb, mode, block, readbytes);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->socket = ap_get_module_config(f->c->conn_config, &core_module);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf rv = apr_socket_timeout_get(ccfg->socket, &saved_sock_timeout);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf rv = apr_socket_timeout_set(ccfg->socket, MIN(time_left, saved_sock_timeout));
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * For a blocking AP_MODE_GETLINE read, apr_brigade_split_line()
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * would loop until a whole line has been read. As this would make it
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * impossible to enforce a total timeout, we only do non-blocking
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE, APR_NONBLOCK_READ, remaining);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (remaining <= 0) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf /* Haven't got a whole line yet, save what we have ... */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->tmpbb = apr_brigade_create(f->c->pool, f->c->bucket_alloc);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf /* ... and wait for more */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf } while (1);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf /* mode != AP_MODE_GETLINE */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf apr_socket_timeout_set(ccfg->socket, saved_sock_timeout);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * If we allow a normal lingering close, the client may keep this
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * process/thread busy for another 30s (MAX_SECS_TO_LINGER).
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * Therefore we tell ap_lingering_close() to shorten this period to
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * 2s (SECONDS_TO_LINGER).
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf apr_table_setn(f->c->notes, "short-lingering-close", "1");
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf cfg = ap_get_module_config(c->base_server->module_config,
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (cfg->header_timeout <= 0 && cfg->body_timeout <= 0) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf /* not configured for this vhost */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ap_set_module_config(c->conn_config, &reqtimeout_module, ccfg);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf /* we are not handling the connection, we just do initialization */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ap_get_module_config(r->connection->conn_config, &reqtimeout_module);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf /* not configured for this connection */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf cfg = ap_get_module_config(r->connection->base_server->module_config,
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ap_get_module_config(r->connection->conn_config, &reqtimeout_module);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf /* not configured for this connection */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf cfg = ap_get_module_config(r->connection->base_server->module_config,
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsfstatic void *reqtimeout_create_srv_config(apr_pool_t *p, server_rec *s)
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf reqtimeout_srv_cfg *cfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg));
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf#define MERGE_INT(cfg, b, a, val) cfg->val = (a->val == -1) ? b->val : a->val;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsfstatic void *reqtimeout_merge_srv_config(apr_pool_t *p, void *base_, void *add_)
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf reqtimeout_srv_cfg *cfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg));
return cfg;
char *endptr;
if (*val < 0) {
return NULL;
apr_pool_t *p,
const char *key,
const char *val)
if (ret)
return ret;
if (rate == 0)
if (ret)
return ret;
if (ret)
return ret;
if (rate)
if (rate)
return ret;
const char *arg)
while (*arg) {
const char *err;
if (!val) {
if (err)
return NULL;
{NULL}