mod_reqtimeout.c revision 53ead8d24845d1e32907c37d1fe58ecf79fb9e50
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 *
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * http://www.apache.org/licenses/LICENSE-2.0
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf *
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.
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf#include "httpd.h"
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf#include "http_config.h"
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf#include "http_request.h"
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf#include "http_connection.h"
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf#include "http_protocol.h"
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf#include "http_log.h"
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf#include "util_filter.h"
3231873d0ba8064a1c90307d810a83ec01a88675jim#define APR_WANT_STRFUNC
3231873d0ba8064a1c90307d810a83ec01a88675jim#include "apr_strings.h"
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsfmodule AP_MODULE_DECLARE_DATA reqtimeout_module;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsftypedef struct
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf{
3231873d0ba8064a1c90307d810a83ec01a88675jim int header_timeout; /* timeout for reading the req hdrs in secs */
3231873d0ba8064a1c90307d810a83ec01a88675jim int header_max_timeout; /* max timeout for req hdrs in secs */
3231873d0ba8064a1c90307d810a83ec01a88675jim int header_min_rate; /* min rate for reading req hdrs in bytes/s */
a4a16f26af59370661ea5f890502cf32146e0947jim apr_time_t header_rate_factor;
3231873d0ba8064a1c90307d810a83ec01a88675jim int body_timeout; /* timeout for reading the req body in secs */
3231873d0ba8064a1c90307d810a83ec01a88675jim int body_max_timeout; /* max timeout for req body in secs */
3231873d0ba8064a1c90307d810a83ec01a88675jim int body_min_rate; /* timeout for reading the req body in secs */
a4a16f26af59370661ea5f890502cf32146e0947jim apr_time_t body_rate_factor;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf} reqtimeout_srv_cfg;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsftypedef struct
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf{
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf apr_time_t timeout_at;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf apr_time_t max_timeout_at;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf int min_rate;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf int new_timeout;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf int new_max_timeout;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf int in_keep_alive;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf char *type;
a4a16f26af59370661ea5f890502cf32146e0947jim apr_time_t rate_factor;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf} reqtimeout_con_cfg;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsftypedef struct
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf{
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf apr_socket_t *socket;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf} reqtimeout_ctx;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsfstatic const char *const reqtimeout_filter_name = "reqtimeout";
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsfstatic void extend_timeout(reqtimeout_con_cfg *ccfg, apr_bucket_brigade *bb)
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf{
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf apr_off_t len;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf apr_time_t new_timeout_at;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (apr_brigade_length(bb, 0, &len) != APR_SUCCESS || len <= 0)
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf return;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
a4a16f26af59370661ea5f890502cf32146e0947jim new_timeout_at = ccfg->timeout_at + len * ccfg->rate_factor;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (ccfg->max_timeout_at > 0 && new_timeout_at > ccfg->max_timeout_at) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->timeout_at = ccfg->max_timeout_at;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf else {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->timeout_at = new_timeout_at;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf}
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsfstatic apr_status_t reqtimeout_filter(ap_filter_t *f,
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf apr_bucket_brigade *bb,
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ap_input_mode_t mode,
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf apr_read_type_e block,
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf apr_off_t readbytes)
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf{
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf reqtimeout_ctx *ctx;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf apr_time_t time_left;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf apr_time_t now;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf apr_status_t rv;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf apr_interval_time_t saved_sock_timeout = -1;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf reqtimeout_con_cfg *ccfg;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ctx = f->ctx;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf AP_DEBUG_ASSERT(ctx != NULL);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg = ap_get_module_config(f->c->conn_config, &reqtimeout_module);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf AP_DEBUG_ASSERT(ccfg != NULL);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (ccfg->in_keep_alive) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf /* For this read, the normal keep-alive timeout must be used */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->in_keep_alive = 0;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf return ap_get_brigade(f->next, bb, mode, block, readbytes);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf now = apr_time_now();
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (ccfg->new_timeout > 0) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf /* set new timeout */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->timeout_at = now + apr_time_from_sec(ccfg->new_timeout);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->new_timeout = 0;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (ccfg->new_max_timeout > 0) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->max_timeout_at = now + apr_time_from_sec(ccfg->new_max_timeout);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->new_max_timeout = 0;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf else if (ccfg->timeout_at == 0) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf /* no timeout set */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf return ap_get_brigade(f->next, bb, mode, block, readbytes);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf time_left = ccfg->timeout_at - now;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (time_left <= 0) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c,
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf "Request %s read timeout", ccfg->type);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf return APR_TIMEUP;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (block == APR_NONBLOCK_READ || mode == AP_MODE_INIT
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf || mode == AP_MODE_EATCRLF) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (ccfg->min_rate > 0 && rv == APR_SUCCESS) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf extend_timeout(ccfg, bb);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf return rv;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (time_left < apr_time_from_sec(1)) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf time_left = apr_time_from_sec(1);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf rv = apr_socket_timeout_get(ctx->socket, &saved_sock_timeout);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf AP_DEBUG_ASSERT(rv == APR_SUCCESS);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (saved_sock_timeout >= time_left) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf rv = apr_socket_timeout_set(ctx->socket, time_left);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf AP_DEBUG_ASSERT(rv == APR_SUCCESS);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf else {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf saved_sock_timeout = -1;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (saved_sock_timeout != -1) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf apr_socket_timeout_set(ctx->socket, saved_sock_timeout);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (ccfg->min_rate > 0 && rv == APR_SUCCESS) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf extend_timeout(ccfg, bb);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (rv == APR_TIMEUP) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c,
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf "Request %s read timeout", ccfg->type);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf return rv;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf}
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsfstatic int reqtimeout_pre_conn(conn_rec *c, void *csd)
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf{
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf reqtimeout_ctx *ctx;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf reqtimeout_con_cfg *ccfg;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf reqtimeout_srv_cfg *cfg;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf cfg = ap_get_module_config(c->base_server->module_config,
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf &reqtimeout_module);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf AP_DEBUG_ASSERT(cfg != NULL);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (cfg->header_timeout <= 0 && cfg->body_timeout <= 0) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf /* not configured for this vhost */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf return OK;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ctx = apr_pcalloc(c->pool, sizeof(reqtimeout_ctx));
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ctx->socket = csd;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg = apr_pcalloc(c->pool, sizeof(reqtimeout_con_cfg));
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->new_timeout = cfg->header_timeout;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->new_max_timeout = cfg->header_max_timeout;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->type = "header";
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->min_rate = cfg->header_min_rate;
a4a16f26af59370661ea5f890502cf32146e0947jim ccfg->rate_factor = cfg->header_rate_factor;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ap_set_module_config(c->conn_config, &reqtimeout_module, ccfg);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ap_add_input_filter("reqtimeout", ctx, NULL, c);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf return OK;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf}
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsfstatic int reqtimeout_after_headers(request_rec *r)
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf{
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf reqtimeout_srv_cfg *cfg;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf reqtimeout_con_cfg *ccfg =
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ap_get_module_config(r->connection->conn_config, &reqtimeout_module);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (ccfg == NULL) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf /* not configured for this vhost */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf return OK;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf cfg = ap_get_module_config(r->connection->base_server->module_config,
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf &reqtimeout_module);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf AP_DEBUG_ASSERT(cfg != NULL);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->timeout_at = 0;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->max_timeout_at = 0;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->new_timeout = cfg->body_timeout;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->new_max_timeout = cfg->body_max_timeout;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->min_rate = cfg->body_min_rate;
a4a16f26af59370661ea5f890502cf32146e0947jim ccfg->rate_factor = cfg->body_rate_factor;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->type = "body";
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf return OK;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf}
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsfstatic int reqtimeout_after_body(request_rec *r)
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf{
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf reqtimeout_srv_cfg *cfg;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf reqtimeout_con_cfg *ccfg =
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ap_get_module_config(r->connection->conn_config, &reqtimeout_module);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (ccfg == NULL) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf /* not configured for this vhost */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf return OK;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf cfg = ap_get_module_config(r->connection->base_server->module_config,
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf &reqtimeout_module);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf AP_DEBUG_ASSERT(cfg != NULL);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->timeout_at = 0;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->max_timeout_at = 0;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->in_keep_alive = 1;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->new_timeout = cfg->header_timeout;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->new_max_timeout = cfg->header_max_timeout;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->min_rate = cfg->header_min_rate;
a4a16f26af59370661ea5f890502cf32146e0947jim ccfg->rate_factor = cfg->header_rate_factor;
a4a16f26af59370661ea5f890502cf32146e0947jim
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ccfg->type = "header";
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf return OK;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf}
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsfstatic void *reqtimeout_create_srv_config(apr_pool_t *p, server_rec *s)
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf{
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf reqtimeout_srv_cfg *cfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg));
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf cfg->header_timeout = -1;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf cfg->header_max_timeout = -1;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf cfg->header_min_rate = -1;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf cfg->body_timeout = -1;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf cfg->body_max_timeout = -1;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf cfg->body_min_rate = -1;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf return cfg;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf}
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
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{
a4a16f26af59370661ea5f890502cf32146e0947jim reqtimeout_srv_cfg *base = base_;
a4a16f26af59370661ea5f890502cf32146e0947jim reqtimeout_srv_cfg *add = add_;
a4a16f26af59370661ea5f890502cf32146e0947jim reqtimeout_srv_cfg *cfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg));
a4a16f26af59370661ea5f890502cf32146e0947jim
a4a16f26af59370661ea5f890502cf32146e0947jim MERGE_INT(cfg, base, add, header_timeout);
a4a16f26af59370661ea5f890502cf32146e0947jim MERGE_INT(cfg, base, add, header_max_timeout);
a4a16f26af59370661ea5f890502cf32146e0947jim MERGE_INT(cfg, base, add, header_min_rate);
a4a16f26af59370661ea5f890502cf32146e0947jim MERGE_INT(cfg, base, add, body_timeout);
a4a16f26af59370661ea5f890502cf32146e0947jim MERGE_INT(cfg, base, add, body_max_timeout);
a4a16f26af59370661ea5f890502cf32146e0947jim MERGE_INT(cfg, base, add, body_min_rate);
a4a16f26af59370661ea5f890502cf32146e0947jim
a4a16f26af59370661ea5f890502cf32146e0947jim cfg->header_rate_factor = (cfg->header_min_rate == -1) ? base->header_rate_factor :
a4a16f26af59370661ea5f890502cf32146e0947jim add->header_rate_factor;
a4a16f26af59370661ea5f890502cf32146e0947jim cfg->body_rate_factor = (cfg->body_min_rate == -1) ? base->body_rate_factor :
a4a16f26af59370661ea5f890502cf32146e0947jim add->body_rate_factor;
a4a16f26af59370661ea5f890502cf32146e0947jim
a4a16f26af59370661ea5f890502cf32146e0947jim return cfg;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf}
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sfstatic const char *parse_int(apr_pool_t *p, const char *arg, int *val) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf char *endptr;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf *val = strtol(arg, &endptr, 10);
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf if (arg == endptr) {
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf return apr_psprintf(p, "Value '%s' not numerical", endptr);
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf }
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf if (*endptr != '\0') {
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf return apr_psprintf(p, "Cannot parse '%s'", endptr);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf if (*val < 0) {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf return "Value must be non-negative";
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf return NULL;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf}
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
3231873d0ba8064a1c90307d810a83ec01a88675jimstatic const char *set_reqtimeout_param(reqtimeout_srv_cfg *conf,
3231873d0ba8064a1c90307d810a83ec01a88675jim apr_pool_t *p,
3231873d0ba8064a1c90307d810a83ec01a88675jim const char *key,
3231873d0ba8064a1c90307d810a83ec01a88675jim const char *val)
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf{
3231873d0ba8064a1c90307d810a83ec01a88675jim const char *ret = NULL;
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf char *rate_str = NULL, *initial_str, *max_str = NULL;
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf int rate = 0, initial = 0, max = 0;
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf enum { PARAM_HEADER, PARAM_BODY } type;
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf if (!strcasecmp(key, "header")) {
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf type = PARAM_HEADER;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf else if (!strcasecmp(key, "body")) {
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf type = PARAM_BODY;
3231873d0ba8064a1c90307d810a83ec01a88675jim }
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf else {
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf return "Unknown RequestReadTimeout parameter";
3231873d0ba8064a1c90307d810a83ec01a88675jim }
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf if ((rate_str = strcasestr(val, ",minrate="))) {
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf initial_str = apr_pstrndup(p, val, rate_str - val);
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf rate_str += strlen(",minrate=");
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf ret = parse_int(p, rate_str, &rate);
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf if (ret)
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf return ret;
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf if (rate == 0)
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf return "Minimum data rate must be larger than 0";
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf if ((max_str = strchr(initial_str, '-'))) {
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf *max_str++ = '\0';
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf ret = parse_int(p, max_str, &max);
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf if (ret)
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf return ret;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf ret = parse_int(p, initial_str, &initial);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf }
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf else {
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf if (ap_strchr_c(val, '-'))
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf return "Must set MinRate option if using timeout range";
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf ret = parse_int(p, val, &initial);
3231873d0ba8064a1c90307d810a83ec01a88675jim }
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf if (ret)
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf return ret;
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf if (max && initial >= max) {
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf return "Maximum timeout must be larger than initial timeout";
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf }
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf if (type == PARAM_HEADER) {
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf conf->header_timeout = initial;
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf conf->header_max_timeout = max;
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf conf->header_min_rate = rate;
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf if (rate)
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf conf->header_rate_factor = apr_time_from_sec(1) / rate;
3231873d0ba8064a1c90307d810a83ec01a88675jim }
3231873d0ba8064a1c90307d810a83ec01a88675jim else {
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf conf->body_timeout = initial;
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf conf->body_max_timeout = max;
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf conf->body_min_rate = rate;
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf if (rate)
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf conf->body_rate_factor = apr_time_from_sec(1) / rate;
3231873d0ba8064a1c90307d810a83ec01a88675jim }
3231873d0ba8064a1c90307d810a83ec01a88675jim return ret;
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf}
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
3231873d0ba8064a1c90307d810a83ec01a88675jimstatic const char *set_reqtimeouts(cmd_parms *cmd, void *mconfig,
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf const char *arg)
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf{
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf reqtimeout_srv_cfg *conf =
3231873d0ba8064a1c90307d810a83ec01a88675jim ap_get_module_config(cmd->server->module_config,
3231873d0ba8064a1c90307d810a83ec01a88675jim &reqtimeout_module);
3231873d0ba8064a1c90307d810a83ec01a88675jim
3231873d0ba8064a1c90307d810a83ec01a88675jim while (*arg) {
3231873d0ba8064a1c90307d810a83ec01a88675jim char *word, *val;
3231873d0ba8064a1c90307d810a83ec01a88675jim const char *err;
3231873d0ba8064a1c90307d810a83ec01a88675jim
3231873d0ba8064a1c90307d810a83ec01a88675jim word = ap_getword_conf(cmd->pool, &arg);
3231873d0ba8064a1c90307d810a83ec01a88675jim val = strchr(word, '=');
3231873d0ba8064a1c90307d810a83ec01a88675jim if (!val) {
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf return "Invalid RequestReadTimeout parameter. Parameter must be "
3231873d0ba8064a1c90307d810a83ec01a88675jim "in the form 'key=value'";
3231873d0ba8064a1c90307d810a83ec01a88675jim }
3231873d0ba8064a1c90307d810a83ec01a88675jim else
3231873d0ba8064a1c90307d810a83ec01a88675jim *val++ = '\0';
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
3231873d0ba8064a1c90307d810a83ec01a88675jim err = set_reqtimeout_param(conf, cmd->pool, word, val);
3231873d0ba8064a1c90307d810a83ec01a88675jim
3231873d0ba8064a1c90307d810a83ec01a88675jim if (err)
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf return apr_psprintf(cmd->temp_pool, "RequestReadTimeout: %s=%s: %s",
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf word, val, err);
3231873d0ba8064a1c90307d810a83ec01a88675jim }
3231873d0ba8064a1c90307d810a83ec01a88675jim
3231873d0ba8064a1c90307d810a83ec01a88675jim return NULL;
3231873d0ba8064a1c90307d810a83ec01a88675jim
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf}
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsfstatic void reqtimeout_hooks(apr_pool_t *pool)
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf{
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf /*
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * mod_ssl is AP_FTYPE_CONNECTION + 5 and mod_reqtimeout needs to
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * be called before mod_ssl. Otherwise repeated reads during the ssl
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf * handshake can prevent the timeout from triggering.
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ap_register_input_filter(reqtimeout_filter_name, reqtimeout_filter, NULL,
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf AP_FTYPE_CONNECTION + 8);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ap_hook_pre_connection(reqtimeout_pre_conn, NULL, NULL, APR_HOOK_MIDDLE);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ap_hook_post_read_request(reqtimeout_after_headers, NULL, NULL,
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf APR_HOOK_MIDDLE);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf ap_hook_log_transaction(reqtimeout_after_body, NULL, NULL,
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf APR_HOOK_MIDDLE);
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf}
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsfstatic const command_rec reqtimeout_cmds[] = {
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf AP_INIT_RAW_ARGS("RequestReadTimeout", set_reqtimeouts, NULL, RSRC_CONF,
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf "Set various timeout parameters for reading request "
53ead8d24845d1e32907c37d1fe58ecf79fb9e50sf "headers and body"),
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf {NULL}
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf};
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsfmodule AP_MODULE_DECLARE_DATA reqtimeout_module = {
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf STANDARD20_MODULE_STUFF,
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf NULL, /* create per-dir config structures */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf NULL, /* merge per-dir config structures */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf reqtimeout_create_srv_config, /* create per-server config structures */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf reqtimeout_merge_srv_config, /* merge per-server config structures */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf reqtimeout_cmds, /* table of config file commands */
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf reqtimeout_hooks
4dee28b6fc8fff5efde4e7821aeb6defed3fb84dsf};