1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define CORE_PRIVATE 18#include "httpd.h" 19#include "http_config.h" 20#include "http_request.h" 21#include "http_connection.h" 22#include "http_protocol.h" 23#include "http_log.h" 24#include "http_core.h" 25#include "util_filter.h" 26#define APR_WANT_STRFUNC 27#include "apr_strings.h" 28#include "apr_version.h" 29 30module AP_MODULE_DECLARE_DATA reqtimeout_module; 31 32typedef struct 33{ 34 int header_timeout; /* timeout for reading the req hdrs in secs */ 35 int header_max_timeout; /* max timeout for req hdrs in secs */ 36 int header_min_rate; /* min rate for reading req hdrs in bytes/s */ 37 apr_time_t header_rate_factor; 38 int body_timeout; /* timeout for reading the req body in secs */ 39 int body_max_timeout; /* max timeout for req body in secs */ 40 int body_min_rate; /* timeout for reading the req body in secs */ 41 apr_time_t body_rate_factor; 42} reqtimeout_srv_cfg; 43 44/* this struct is used both as conn_config and as filter context */ 45typedef struct 46{ 47 apr_time_t timeout_at; 48 apr_time_t max_timeout_at; 49 int min_rate; 50 int new_timeout; 51 int new_max_timeout; 52 int in_keep_alive; 53 char *type; 54 apr_socket_t *socket; 55 apr_time_t rate_factor; 56 apr_bucket_brigade *tmpbb; 57} reqtimeout_con_cfg; 58 59static const char *const reqtimeout_filter_name = "reqtimeout"; 60 61static void extend_timeout(reqtimeout_con_cfg *ccfg, apr_bucket_brigade *bb) 62{ 63 apr_off_t len; 64 apr_time_t new_timeout_at; 65 66 if (apr_brigade_length(bb, 0, &len) != APR_SUCCESS || len <= 0) 67 return; 68 69 new_timeout_at = ccfg->timeout_at + len * ccfg->rate_factor; 70 if (ccfg->max_timeout_at > 0 && new_timeout_at > ccfg->max_timeout_at) { 71 ccfg->timeout_at = ccfg->max_timeout_at; 72 } 73 else { 74 ccfg->timeout_at = new_timeout_at; 75 } 76} 77 78static apr_status_t check_time_left(reqtimeout_con_cfg *ccfg, 79 apr_time_t *time_left_p) 80{ 81 *time_left_p = ccfg->timeout_at - apr_time_now(); 82 if (*time_left_p <= 0) 83 return APR_TIMEUP; 84 85 if (*time_left_p < apr_time_from_sec(1)) { 86 *time_left_p = apr_time_from_sec(1); 87 } 88 return APR_SUCCESS; 89} 90 91static apr_status_t have_lf_or_eos(apr_bucket_brigade *bb) 92{ 93 apr_bucket *b = APR_BRIGADE_LAST(bb); 94 95 for ( ; b != APR_BRIGADE_SENTINEL(bb) ; b = APR_BUCKET_PREV(b) ) { 96 const char *str; 97 apr_size_t len; 98 apr_status_t rv; 99 100 if (APR_BUCKET_IS_EOS(b)) 101 return APR_SUCCESS; 102 103 if (APR_BUCKET_IS_METADATA(b)) 104 continue; 105 106 rv = apr_bucket_read(b, &str, &len, APR_BLOCK_READ); 107 if (rv != APR_SUCCESS) 108 return rv; 109 110 if (len == 0) 111 continue; 112 113 if (str[len-1] == APR_ASCII_LF) 114 return APR_SUCCESS; 115 } 116 return APR_INCOMPLETE; 117} 118 119/* 120 * Append bbIn to bbOut and merge small buckets, to avoid DoS by high memory 121 * usage 122 */ 123static apr_status_t brigade_append(apr_bucket_brigade *bbOut, apr_bucket_brigade *bbIn) 124{ 125 while (!APR_BRIGADE_EMPTY(bbIn)) { 126 apr_bucket *e = APR_BRIGADE_FIRST(bbIn); 127 const char *str; 128 apr_size_t len; 129 apr_status_t rv; 130 131 rv = apr_bucket_read(e, &str, &len, APR_BLOCK_READ); 132 if (rv != APR_SUCCESS) { 133 return rv; 134 } 135 136 APR_BUCKET_REMOVE(e); 137 if (APR_BUCKET_IS_METADATA(e) || len > APR_BUCKET_BUFF_SIZE/4) { 138 APR_BRIGADE_INSERT_TAIL(bbOut, e); 139 } 140 else { 141 if (len > 0) { 142 rv = apr_brigade_write(bbOut, NULL, NULL, str, len); 143 if (rv != APR_SUCCESS) { 144 apr_bucket_destroy(e); 145 return rv; 146 } 147 } 148 apr_bucket_destroy(e); 149 } 150 } 151 return APR_SUCCESS; 152} 153 154 155#define MIN(x,y) ((x) < (y) ? (x) : (y)) 156static apr_status_t reqtimeout_filter(ap_filter_t *f, 157 apr_bucket_brigade *bb, 158 ap_input_mode_t mode, 159 apr_read_type_e block, 160 apr_off_t readbytes) 161{ 162 apr_time_t time_left; 163 apr_time_t now; 164 apr_status_t rv; 165 apr_interval_time_t saved_sock_timeout = -1; 166 reqtimeout_con_cfg *ccfg = f->ctx; 167 168 if (ccfg->in_keep_alive) { 169 /* For this read, the normal keep-alive timeout must be used */ 170 ccfg->in_keep_alive = 0; 171 return ap_get_brigade(f->next, bb, mode, block, readbytes); 172 } 173 174 now = apr_time_now(); 175 if (ccfg->new_timeout > 0) { 176 /* set new timeout */ 177 ccfg->timeout_at = now + apr_time_from_sec(ccfg->new_timeout); 178 ccfg->new_timeout = 0; 179 if (ccfg->new_max_timeout > 0) { 180 ccfg->max_timeout_at = now + apr_time_from_sec(ccfg->new_max_timeout); 181 ccfg->new_max_timeout = 0; 182 } 183 } 184 else if (ccfg->timeout_at == 0) { 185 /* no timeout set */ 186 return ap_get_brigade(f->next, bb, mode, block, readbytes); 187 } 188 189 if (!ccfg->socket) { 190 ccfg->socket = ap_get_module_config(f->c->conn_config, &core_module); 191 } 192 193 rv = check_time_left(ccfg, &time_left); 194 if (rv != APR_SUCCESS) 195 goto out; 196 197 if (block == APR_NONBLOCK_READ || mode == AP_MODE_INIT 198 || mode == AP_MODE_EATCRLF) { 199 rv = ap_get_brigade(f->next, bb, mode, block, readbytes); 200 if (ccfg->min_rate > 0 && rv == APR_SUCCESS) { 201 extend_timeout(ccfg, bb); 202 } 203 return rv; 204 } 205 206 rv = apr_socket_timeout_get(ccfg->socket, &saved_sock_timeout); 207 AP_DEBUG_ASSERT(rv == APR_SUCCESS); 208 209 rv = apr_socket_timeout_set(ccfg->socket, MIN(time_left, saved_sock_timeout)); 210 AP_DEBUG_ASSERT(rv == APR_SUCCESS); 211 212 if (mode == AP_MODE_GETLINE) { 213 /* 214 * For a blocking AP_MODE_GETLINE read, apr_brigade_split_line() 215 * would loop until a whole line has been read. As this would make it 216 * impossible to enforce a total timeout, we only do non-blocking 217 * reads. 218 */ 219 apr_off_t remaining = HUGE_STRING_LEN; 220 do { 221 apr_off_t bblen; 222#if APR_MAJOR_VERSION < 2 223 apr_int32_t nsds; 224 apr_interval_time_t poll_timeout; 225 apr_pollfd_t pollset; 226#endif 227 228 rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE, APR_NONBLOCK_READ, remaining); 229 if (rv != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(rv)) { 230 break; 231 } 232 233 if (!APR_BRIGADE_EMPTY(bb)) { 234 if (ccfg->min_rate > 0) { 235 extend_timeout(ccfg, bb); 236 } 237 238 rv = have_lf_or_eos(bb); 239 if (rv != APR_INCOMPLETE) { 240 break; 241 } 242 243 rv = apr_brigade_length(bb, 1, &bblen); 244 if (rv != APR_SUCCESS) { 245 break; 246 } 247 remaining -= bblen; 248 if (remaining <= 0) { 249 break; 250 } 251 252 /* Haven't got a whole line yet, save what we have ... */ 253 if (!ccfg->tmpbb) { 254 ccfg->tmpbb = apr_brigade_create(f->c->pool, f->c->bucket_alloc); 255 } 256 rv = brigade_append(ccfg->tmpbb, bb); 257 if (rv != APR_SUCCESS) 258 break; 259 } 260 261 /* ... and wait for more */ 262#if APR_MAJOR_VERSION < 2 263 pollset.p = f->c->pool; 264 pollset.desc_type = APR_POLL_SOCKET; 265 pollset.reqevents = APR_POLLIN|APR_POLLHUP; 266 pollset.desc.s = ccfg->socket; 267 apr_socket_timeout_get(ccfg->socket, &poll_timeout); 268 rv = apr_poll(&pollset, 1, &nsds, poll_timeout); 269#else 270 rv = apr_socket_wait(ccfg->socket, APR_WAIT_READ); 271#endif 272 if (rv != APR_SUCCESS) 273 break; 274 275 rv = check_time_left(ccfg, &time_left); 276 if (rv != APR_SUCCESS) 277 break; 278 279 rv = apr_socket_timeout_set(ccfg->socket, 280 MIN(time_left, saved_sock_timeout)); 281 AP_DEBUG_ASSERT(rv == APR_SUCCESS); 282 283 } while (1); 284 285 if (ccfg->tmpbb) 286 APR_BRIGADE_PREPEND(bb, ccfg->tmpbb); 287 288 } 289 else { 290 /* mode != AP_MODE_GETLINE */ 291 rv = ap_get_brigade(f->next, bb, mode, block, readbytes); 292 if (ccfg->min_rate > 0 && rv == APR_SUCCESS) { 293 extend_timeout(ccfg, bb); 294 } 295 } 296 297 apr_socket_timeout_set(ccfg->socket, saved_sock_timeout); 298 299out: 300 if (APR_STATUS_IS_TIMEUP(rv)) { 301 ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c, 302 "Request %s read timeout", ccfg->type); 303 /* 304 * If we allow a normal lingering close, the client may keep this 305 * process/thread busy for another 30s (MAX_SECS_TO_LINGER). 306 * Therefore we tell ap_lingering_close() to shorten this period to 307 * 2s (SECONDS_TO_LINGER). 308 */ 309 apr_table_setn(f->c->notes, "short-lingering-close", "1"); 310 311 /* 312 * Also, we must not allow keep-alive requests, as 313 * ap_finalize_protocol() may ignore our error status (if the timeout 314 * happened on a request body that is discarded). 315 */ 316 f->c->keepalive = AP_CONN_CLOSE; 317 } 318 return rv; 319} 320 321static int reqtimeout_init(conn_rec *c) 322{ 323 reqtimeout_con_cfg *ccfg; 324 reqtimeout_srv_cfg *cfg; 325 326 cfg = ap_get_module_config(c->base_server->module_config, 327 &reqtimeout_module); 328 AP_DEBUG_ASSERT(cfg != NULL); 329 if (cfg->header_timeout <= 0 && cfg->body_timeout <= 0) { 330 /* not configured for this vhost */ 331 return DECLINED; 332 } 333 334 ccfg = apr_pcalloc(c->pool, sizeof(reqtimeout_con_cfg)); 335 ccfg->new_timeout = cfg->header_timeout; 336 ccfg->new_max_timeout = cfg->header_max_timeout; 337 ccfg->type = "header"; 338 ccfg->min_rate = cfg->header_min_rate; 339 ccfg->rate_factor = cfg->header_rate_factor; 340 ap_set_module_config(c->conn_config, &reqtimeout_module, ccfg); 341 342 ap_add_input_filter("reqtimeout", ccfg, NULL, c); 343 /* we are not handling the connection, we just do initialization */ 344 return DECLINED; 345} 346 347static int reqtimeout_after_headers(request_rec *r) 348{ 349 reqtimeout_srv_cfg *cfg; 350 reqtimeout_con_cfg *ccfg = 351 ap_get_module_config(r->connection->conn_config, &reqtimeout_module); 352 353 if (ccfg == NULL) { 354 /* not configured for this connection */ 355 return OK; 356 } 357 358 cfg = ap_get_module_config(r->connection->base_server->module_config, 359 &reqtimeout_module); 360 AP_DEBUG_ASSERT(cfg != NULL); 361 362 ccfg->timeout_at = 0; 363 ccfg->max_timeout_at = 0; 364 if (r->method_number != M_CONNECT) { 365 ccfg->new_timeout = cfg->body_timeout; 366 ccfg->new_max_timeout = cfg->body_max_timeout; 367 ccfg->min_rate = cfg->body_min_rate; 368 ccfg->rate_factor = cfg->body_rate_factor; 369 ccfg->type = "body"; 370 } 371 372 return OK; 373} 374 375static int reqtimeout_after_body(request_rec *r) 376{ 377 reqtimeout_srv_cfg *cfg; 378 reqtimeout_con_cfg *ccfg = 379 ap_get_module_config(r->connection->conn_config, &reqtimeout_module); 380 381 if (ccfg == NULL) { 382 /* not configured for this connection */ 383 return OK; 384 } 385 386 cfg = ap_get_module_config(r->connection->base_server->module_config, 387 &reqtimeout_module); 388 AP_DEBUG_ASSERT(cfg != NULL); 389 390 ccfg->timeout_at = 0; 391 ccfg->max_timeout_at = 0; 392 ccfg->in_keep_alive = 1; 393 ccfg->new_timeout = cfg->header_timeout; 394 ccfg->new_max_timeout = cfg->header_max_timeout; 395 ccfg->min_rate = cfg->header_min_rate; 396 ccfg->rate_factor = cfg->header_rate_factor; 397 398 ccfg->type = "header"; 399 400 return OK; 401} 402 403static void *reqtimeout_create_srv_config(apr_pool_t *p, server_rec *s) 404{ 405 reqtimeout_srv_cfg *cfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg)); 406 407 cfg->header_timeout = -1; 408 cfg->header_max_timeout = -1; 409 cfg->header_min_rate = -1; 410 cfg->body_timeout = -1; 411 cfg->body_max_timeout = -1; 412 cfg->body_min_rate = -1; 413 414 return cfg; 415} 416 417#define MERGE_INT(cfg, b, a, val) cfg->val = (a->val == -1) ? b->val : a->val; 418static void *reqtimeout_merge_srv_config(apr_pool_t *p, void *base_, void *add_) 419{ 420 reqtimeout_srv_cfg *base = base_; 421 reqtimeout_srv_cfg *add = add_; 422 reqtimeout_srv_cfg *cfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg)); 423 424 MERGE_INT(cfg, base, add, header_timeout); 425 MERGE_INT(cfg, base, add, header_max_timeout); 426 MERGE_INT(cfg, base, add, header_min_rate); 427 MERGE_INT(cfg, base, add, body_timeout); 428 MERGE_INT(cfg, base, add, body_max_timeout); 429 MERGE_INT(cfg, base, add, body_min_rate); 430 431 cfg->header_rate_factor = (cfg->header_min_rate == -1) ? base->header_rate_factor : 432 add->header_rate_factor; 433 cfg->body_rate_factor = (cfg->body_min_rate == -1) ? base->body_rate_factor : 434 add->body_rate_factor; 435 436 return cfg; 437} 438 439static const char *parse_int(apr_pool_t *p, const char *arg, int *val) { 440 char *endptr; 441 *val = strtol(arg, &endptr, 10); 442 443 if (arg == endptr) { 444 return apr_psprintf(p, "Value '%s' not numerical", endptr); 445 } 446 if (*endptr != '\0') { 447 return apr_psprintf(p, "Cannot parse '%s'", endptr); 448 } 449 if (*val < 0) { 450 return "Value must be non-negative"; 451 } 452 return NULL; 453} 454 455static const char *set_reqtimeout_param(reqtimeout_srv_cfg *conf, 456 apr_pool_t *p, 457 const char *key, 458 const char *val) 459{ 460 const char *ret = NULL; 461 char *rate_str = NULL, *initial_str, *max_str = NULL; 462 int rate = 0, initial = 0, max = 0; 463 enum { PARAM_HEADER, PARAM_BODY } type; 464 465 if (!strcasecmp(key, "header")) { 466 type = PARAM_HEADER; 467 } 468 else if (!strcasecmp(key, "body")) { 469 type = PARAM_BODY; 470 } 471 else { 472 return "Unknown RequestReadTimeout parameter"; 473 } 474 475 if ((rate_str = ap_strcasestr(val, ",minrate="))) { 476 initial_str = apr_pstrndup(p, val, rate_str - val); 477 rate_str += strlen(",minrate="); 478 ret = parse_int(p, rate_str, &rate); 479 if (ret) 480 return ret; 481 482 if (rate == 0) 483 return "Minimum data rate must be larger than 0"; 484 485 if ((max_str = strchr(initial_str, '-'))) { 486 *max_str++ = '\0'; 487 ret = parse_int(p, max_str, &max); 488 if (ret) 489 return ret; 490 } 491 492 ret = parse_int(p, initial_str, &initial); 493 } 494 else { 495 if (ap_strchr_c(val, '-')) 496 return "Must set MinRate option if using timeout range"; 497 ret = parse_int(p, val, &initial); 498 } 499 500 if (ret) 501 return ret; 502 503 if (max && initial >= max) { 504 return "Maximum timeout must be larger than initial timeout"; 505 } 506 507 if (type == PARAM_HEADER) { 508 conf->header_timeout = initial; 509 conf->header_max_timeout = max; 510 conf->header_min_rate = rate; 511 if (rate) 512 conf->header_rate_factor = apr_time_from_sec(1) / rate; 513 } 514 else { 515 conf->body_timeout = initial; 516 conf->body_max_timeout = max; 517 conf->body_min_rate = rate; 518 if (rate) 519 conf->body_rate_factor = apr_time_from_sec(1) / rate; 520 } 521 return ret; 522} 523 524static const char *set_reqtimeouts(cmd_parms *cmd, void *mconfig, 525 const char *arg) 526{ 527 reqtimeout_srv_cfg *conf = 528 ap_get_module_config(cmd->server->module_config, 529 &reqtimeout_module); 530 531 while (*arg) { 532 char *word, *val; 533 const char *err; 534 535 word = ap_getword_conf(cmd->pool, &arg); 536 val = strchr(word, '='); 537 if (!val) { 538 return "Invalid RequestReadTimeout parameter. Parameter must be " 539 "in the form 'key=value'"; 540 } 541 else 542 *val++ = '\0'; 543 544 err = set_reqtimeout_param(conf, cmd->pool, word, val); 545 546 if (err) 547 return apr_psprintf(cmd->temp_pool, "RequestReadTimeout: %s=%s: %s", 548 word, val, err); 549 } 550 551 return NULL; 552 553} 554 555static void reqtimeout_hooks(apr_pool_t *pool) 556{ 557 /* 558 * mod_ssl is AP_FTYPE_CONNECTION + 5 and mod_reqtimeout needs to 559 * be called before mod_ssl. Otherwise repeated reads during the ssl 560 * handshake can prevent the timeout from triggering. 561 */ 562 ap_register_input_filter(reqtimeout_filter_name, reqtimeout_filter, NULL, 563 AP_FTYPE_CONNECTION + 8); 564 565 /* 566 * mod_reqtimeout needs to be called before ap_process_http_request (which 567 * is run at APR_HOOK_REALLY_LAST) but after all other protocol modules. 568 * This ensures that it only influences normal http connections and not 569 * e.g. mod_ftp. Also, if mod_reqtimeout used the pre_connection hook, it 570 * would be inserted on mod_proxy's backend connections. 571 */ 572 ap_hook_process_connection(reqtimeout_init, NULL, NULL, APR_HOOK_LAST); 573 574 ap_hook_post_read_request(reqtimeout_after_headers, NULL, NULL, 575 APR_HOOK_MIDDLE); 576 ap_hook_log_transaction(reqtimeout_after_body, NULL, NULL, 577 APR_HOOK_MIDDLE); 578} 579 580static const command_rec reqtimeout_cmds[] = { 581 AP_INIT_RAW_ARGS("RequestReadTimeout", set_reqtimeouts, NULL, RSRC_CONF, 582 "Set various timeout parameters for reading request " 583 "headers and body"), 584 {NULL} 585}; 586 587module AP_MODULE_DECLARE_DATA reqtimeout_module = { 588 STANDARD20_MODULE_STUFF, 589 NULL, /* create per-dir config structures */ 590 NULL, /* merge per-dir config structures */ 591 reqtimeout_create_srv_config, /* create per-server config structures */ 592 reqtimeout_merge_srv_config, /* merge per-server config structures */ 593 reqtimeout_cmds, /* table of config file commands */ 594 reqtimeout_hooks 595}; 596