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 #include "httpd.h"
18 #include "http_config.h"
19 #include "http_request.h"
20 #include "http_connection.h"
21 #include "http_protocol.h"
22 #include "http_log.h"
23 #include "http_core.h"
24 #include "util_filter.h"
25 #define APR_WANT_STRFUNC
26 #include "apr_strings.h"
27 #include "apr_version.h"
28
29 module AP_MODULE_DECLARE_DATA reqtimeout_module;
30
31 #define UNSET -1
32 #define MRT_DEFAULT_handshake_TIMEOUT 0 /* disabled */
33 #define MRT_DEFAULT_handshake_MAX_TIMEOUT 0
34 #define MRT_DEFAULT_handshake_MIN_RATE 0
35 #define MRT_DEFAULT_header_TIMEOUT 20
36 #define MRT_DEFAULT_header_MAX_TIMEOUT 40
37 #define MRT_DEFAULT_header_MIN_RATE 500
38 #define MRT_DEFAULT_body_TIMEOUT 20
39 #define MRT_DEFAULT_body_MAX_TIMEOUT 0
40 #define MRT_DEFAULT_body_MIN_RATE 500
41
42 typedef struct
43 {
44 int timeout; /* timeout in secs */
45 int max_timeout; /* max timeout in secs */
46 int min_rate; /* min rate in bytes/s */
47 apr_time_t rate_factor; /* scale factor (#usecs per min_rate) */
48 } reqtimeout_stage_t;
49
50 typedef struct
51 {
52 reqtimeout_stage_t handshake; /* Handshaking (TLS) */
53 reqtimeout_stage_t header; /* Reading the HTTP header */
54 reqtimeout_stage_t body; /* Reading the HTTP body */
55 } reqtimeout_srv_cfg;
56
57 /* this struct is used both as conn_config and as filter context */
58 typedef struct
59 {
60 apr_time_t timeout_at;
61 apr_time_t max_timeout_at;
62 reqtimeout_stage_t cur_stage;
63 int in_keep_alive;
64 char *type;
65 apr_socket_t *socket;
66 apr_bucket_brigade *tmpbb;
67 } reqtimeout_con_cfg;
68
69 static const char *const reqtimeout_filter_name = "reqtimeout";
70 static int default_handshake_rate_factor;
71 static int default_header_rate_factor;
72 static int default_body_rate_factor;
73
extend_timeout(reqtimeout_con_cfg * ccfg,apr_bucket_brigade * bb)74 static void extend_timeout(reqtimeout_con_cfg *ccfg, apr_bucket_brigade *bb)
75 {
76 apr_off_t len;
77 apr_time_t new_timeout_at;
78
79 if (apr_brigade_length(bb, 0, &len) != APR_SUCCESS || len <= 0)
80 return;
81
82 new_timeout_at = ccfg->timeout_at + len * ccfg->cur_stage.rate_factor;
83 if (ccfg->max_timeout_at > 0 && new_timeout_at > ccfg->max_timeout_at) {
84 ccfg->timeout_at = ccfg->max_timeout_at;
85 }
86 else {
87 ccfg->timeout_at = new_timeout_at;
88 }
89 }
90
check_time_left(reqtimeout_con_cfg * ccfg,apr_time_t * time_left_p,apr_time_t now)91 static apr_status_t check_time_left(reqtimeout_con_cfg *ccfg,
92 apr_time_t *time_left_p,
93 apr_time_t now)
94 {
95 if (!now)
96 now = apr_time_now();
97 *time_left_p = ccfg->timeout_at - now;
98 if (*time_left_p <= 0)
99 return APR_TIMEUP;
100
101 if (*time_left_p < apr_time_from_sec(1)) {
102 *time_left_p = apr_time_from_sec(1);
103 }
104 return APR_SUCCESS;
105 }
106
have_lf_or_eos(apr_bucket_brigade * bb)107 static apr_status_t have_lf_or_eos(apr_bucket_brigade *bb)
108 {
109 apr_bucket *b = APR_BRIGADE_LAST(bb);
110
111 for ( ; b != APR_BRIGADE_SENTINEL(bb) ; b = APR_BUCKET_PREV(b) ) {
112 const char *str;
113 apr_size_t len;
114 apr_status_t rv;
115
116 if (APR_BUCKET_IS_EOS(b))
117 return APR_SUCCESS;
118
119 if (APR_BUCKET_IS_METADATA(b))
120 continue;
121
122 rv = apr_bucket_read(b, &str, &len, APR_BLOCK_READ);
123 if (rv != APR_SUCCESS)
124 return rv;
125
126 if (len == 0)
127 continue;
128
129 if (str[len-1] == APR_ASCII_LF)
130 return APR_SUCCESS;
131 }
132 return APR_INCOMPLETE;
133 }
134
135 /*
136 * Append bbIn to bbOut and merge small buckets, to avoid DoS by high memory
137 * usage
138 */
brigade_append(apr_bucket_brigade * bbOut,apr_bucket_brigade * bbIn)139 static apr_status_t brigade_append(apr_bucket_brigade *bbOut, apr_bucket_brigade *bbIn)
140 {
141 while (!APR_BRIGADE_EMPTY(bbIn)) {
142 apr_bucket *e = APR_BRIGADE_FIRST(bbIn);
143 const char *str;
144 apr_size_t len;
145 apr_status_t rv;
146
147 rv = apr_bucket_read(e, &str, &len, APR_BLOCK_READ);
148 if (rv != APR_SUCCESS) {
149 return rv;
150 }
151
152 APR_BUCKET_REMOVE(e);
153 if (APR_BUCKET_IS_METADATA(e) || len > APR_BUCKET_BUFF_SIZE/4) {
154 APR_BRIGADE_INSERT_TAIL(bbOut, e);
155 }
156 else {
157 if (len > 0) {
158 rv = apr_brigade_write(bbOut, NULL, NULL, str, len);
159 if (rv != APR_SUCCESS) {
160 apr_bucket_destroy(e);
161 return rv;
162 }
163 }
164 apr_bucket_destroy(e);
165 }
166 }
167 return APR_SUCCESS;
168 }
169
170
171 #define MIN(x,y) ((x) < (y) ? (x) : (y))
reqtimeout_filter(ap_filter_t * f,apr_bucket_brigade * bb,ap_input_mode_t mode,apr_read_type_e block,apr_off_t readbytes)172 static apr_status_t reqtimeout_filter(ap_filter_t *f,
173 apr_bucket_brigade *bb,
174 ap_input_mode_t mode,
175 apr_read_type_e block,
176 apr_off_t readbytes)
177 {
178 apr_time_t time_left;
179 apr_time_t now = 0;
180 apr_status_t rv;
181 apr_interval_time_t saved_sock_timeout = UNSET;
182 reqtimeout_con_cfg *ccfg = f->ctx;
183
184 if (ccfg->in_keep_alive) {
185 /* For this read[_request line()], wait for the first byte using the
186 * normal keep-alive timeout (hence don't take this expected idle time
187 * into account to setup the connection expiry below).
188 */
189 ccfg->in_keep_alive = 0;
190 rv = ap_get_brigade(f->next, bb, AP_MODE_SPECULATIVE, block, 1);
191 if (rv != APR_SUCCESS || APR_BRIGADE_EMPTY(bb)) {
192 return rv;
193 }
194 apr_brigade_cleanup(bb);
195 }
196
197 if (ccfg->cur_stage.timeout > 0) {
198 /* set new timeout */
199 now = apr_time_now();
200 ccfg->timeout_at = now + apr_time_from_sec(ccfg->cur_stage.timeout);
201 ccfg->cur_stage.timeout = 0;
202 if (ccfg->cur_stage.max_timeout > 0) {
203 ccfg->max_timeout_at = now + apr_time_from_sec(ccfg->cur_stage.max_timeout);
204 ccfg->cur_stage.max_timeout = 0;
205 }
206 }
207 else if (ccfg->timeout_at == 0) {
208 /* no timeout set, or in between requests */
209 return ap_get_brigade(f->next, bb, mode, block, readbytes);
210 }
211
212 if (!ccfg->socket) {
213 ccfg->socket = ap_get_conn_socket(f->c);
214 }
215
216 rv = check_time_left(ccfg, &time_left, now);
217 if (rv != APR_SUCCESS)
218 goto out;
219
220 if (block == APR_NONBLOCK_READ || mode == AP_MODE_INIT
221 || mode == AP_MODE_EATCRLF) {
222 rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
223 if (ccfg->cur_stage.rate_factor && rv == APR_SUCCESS) {
224 extend_timeout(ccfg, bb);
225 }
226 return rv;
227 }
228
229 rv = apr_socket_timeout_get(ccfg->socket, &saved_sock_timeout);
230 AP_DEBUG_ASSERT(rv == APR_SUCCESS);
231
232 rv = apr_socket_timeout_set(ccfg->socket, MIN(time_left, saved_sock_timeout));
233 AP_DEBUG_ASSERT(rv == APR_SUCCESS);
234
235 if (mode == AP_MODE_GETLINE) {
236 /*
237 * For a blocking AP_MODE_GETLINE read, apr_brigade_split_line()
238 * would loop until a whole line has been read. As this would make it
239 * impossible to enforce a total timeout, we only do non-blocking
240 * reads.
241 */
242 apr_off_t remaining = HUGE_STRING_LEN;
243 do {
244 apr_off_t bblen;
245 #if APR_MAJOR_VERSION < 2
246 apr_int32_t nsds;
247 apr_interval_time_t poll_timeout;
248 apr_pollfd_t pollset;
249 #endif
250
251 rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE, APR_NONBLOCK_READ, remaining);
252 if (rv != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(rv)) {
253 break;
254 }
255
256 if (!APR_BRIGADE_EMPTY(bb)) {
257 if (ccfg->cur_stage.rate_factor) {
258 extend_timeout(ccfg, bb);
259 }
260
261 rv = have_lf_or_eos(bb);
262 if (rv != APR_INCOMPLETE) {
263 break;
264 }
265
266 rv = apr_brigade_length(bb, 1, &bblen);
267 if (rv != APR_SUCCESS) {
268 break;
269 }
270 remaining -= bblen;
271 if (remaining <= 0) {
272 break;
273 }
274
275 /* Haven't got a whole line yet, save what we have ... */
276 if (!ccfg->tmpbb) {
277 ccfg->tmpbb = apr_brigade_create(f->c->pool, f->c->bucket_alloc);
278 }
279 rv = brigade_append(ccfg->tmpbb, bb);
280 if (rv != APR_SUCCESS)
281 break;
282 }
283
284 /* ... and wait for more */
285 #if APR_MAJOR_VERSION < 2
286 pollset.p = f->c->pool;
287 pollset.desc_type = APR_POLL_SOCKET;
288 pollset.reqevents = APR_POLLIN|APR_POLLHUP;
289 pollset.desc.s = ccfg->socket;
290 apr_socket_timeout_get(ccfg->socket, &poll_timeout);
291 rv = apr_poll(&pollset, 1, &nsds, poll_timeout);
292 #else
293 rv = apr_socket_wait(ccfg->socket, APR_WAIT_READ);
294 #endif
295 if (rv != APR_SUCCESS)
296 break;
297
298 rv = check_time_left(ccfg, &time_left, 0);
299 if (rv != APR_SUCCESS)
300 break;
301
302 rv = apr_socket_timeout_set(ccfg->socket,
303 MIN(time_left, saved_sock_timeout));
304 AP_DEBUG_ASSERT(rv == APR_SUCCESS);
305
306 } while (1);
307
308 if (ccfg->tmpbb)
309 APR_BRIGADE_PREPEND(bb, ccfg->tmpbb);
310
311 }
312 else { /* mode != AP_MODE_GETLINE */
313 rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
314 /* Don't extend the timeout in speculative mode, wait for
315 * the real (relevant) bytes to be asked later, within the
316 * currently allotted time.
317 */
318 if (ccfg->cur_stage.rate_factor && rv == APR_SUCCESS
319 && mode != AP_MODE_SPECULATIVE) {
320 extend_timeout(ccfg, bb);
321 }
322 }
323
324 apr_socket_timeout_set(ccfg->socket, saved_sock_timeout);
325
326 out:
327 if (APR_STATUS_IS_TIMEUP(rv)) {
328 ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c, APLOGNO(01382)
329 "Request %s read timeout", ccfg->type);
330 /*
331 * If we allow a normal lingering close, the client may keep this
332 * process/thread busy for another 30s (MAX_SECS_TO_LINGER).
333 * Therefore we tell ap_lingering_close() to shorten this period to
334 * 2s (SECONDS_TO_LINGER).
335 */
336 apr_table_setn(f->c->notes, "short-lingering-close", "1");
337
338 /*
339 * Also, we must not allow keep-alive requests, as
340 * ap_finalize_protocol() may ignore our error status (if the timeout
341 * happened on a request body that is discarded).
342 */
343 f->c->keepalive = AP_CONN_CLOSE;
344 }
345 return rv;
346 }
347
reqtimeout_eor(ap_filter_t * f,apr_bucket_brigade * bb)348 static apr_status_t reqtimeout_eor(ap_filter_t *f, apr_bucket_brigade *bb)
349 {
350 if (!APR_BRIGADE_EMPTY(bb) && AP_BUCKET_IS_EOR(APR_BRIGADE_LAST(bb))) {
351 reqtimeout_con_cfg *ccfg = f->ctx;
352 ccfg->timeout_at = 0;
353 }
354 return ap_pass_brigade(f->next, bb);
355 }
356
357 #define INIT_STAGE(cfg, ccfg, stage) do { \
358 if (cfg->stage.timeout != UNSET) { \
359 ccfg->cur_stage.timeout = cfg->stage.timeout; \
360 ccfg->cur_stage.max_timeout = cfg->stage.max_timeout; \
361 ccfg->cur_stage.rate_factor = cfg->stage.rate_factor; \
362 } \
363 else { \
364 ccfg->cur_stage.timeout = MRT_DEFAULT_##stage##_TIMEOUT; \
365 ccfg->cur_stage.max_timeout = MRT_DEFAULT_##stage##_MAX_TIMEOUT; \
366 ccfg->cur_stage.rate_factor = default_##stage##_rate_factor; \
367 } \
368 } while (0)
369
reqtimeout_init(conn_rec * c)370 static int reqtimeout_init(conn_rec *c)
371 {
372 reqtimeout_con_cfg *ccfg;
373 reqtimeout_srv_cfg *cfg;
374
375 cfg = ap_get_module_config(c->base_server->module_config,
376 &reqtimeout_module);
377 AP_DEBUG_ASSERT(cfg != NULL);
378
379 /* For compatibility, handshake timeout is disabled when UNSET (< 0) */
380 if (cfg->handshake.timeout <= 0
381 && cfg->header.timeout == 0
382 && cfg->body.timeout == 0) {
383 /* disabled for this vhost */
384 return DECLINED;
385 }
386
387 ccfg = ap_get_module_config(c->conn_config, &reqtimeout_module);
388 if (ccfg == NULL) {
389 ccfg = apr_pcalloc(c->pool, sizeof(reqtimeout_con_cfg));
390 ap_set_module_config(c->conn_config, &reqtimeout_module, ccfg);
391 ap_add_output_filter(reqtimeout_filter_name, ccfg, NULL, c);
392 ap_add_input_filter(reqtimeout_filter_name, ccfg, NULL, c);
393
394 ccfg->type = "handshake";
395 if (cfg->handshake.timeout > 0) {
396 INIT_STAGE(cfg, ccfg, handshake);
397 }
398 }
399
400 /* we are not handling the connection, we just do initialization */
401 return DECLINED;
402 }
403
reqtimeout_before_header(request_rec * r,conn_rec * c)404 static void reqtimeout_before_header(request_rec *r, conn_rec *c)
405 {
406 reqtimeout_srv_cfg *cfg;
407 reqtimeout_con_cfg *ccfg =
408 ap_get_module_config(c->conn_config, &reqtimeout_module);
409
410 if (ccfg == NULL) {
411 /* not configured for this connection */
412 return;
413 }
414
415 cfg = ap_get_module_config(c->base_server->module_config,
416 &reqtimeout_module);
417 AP_DEBUG_ASSERT(cfg != NULL);
418
419 /* (Re)set the state for this new request, but ccfg->socket and
420 * ccfg->tmpbb which have the lifetime of the connection.
421 */
422 ccfg->type = "header";
423 ccfg->timeout_at = 0;
424 ccfg->max_timeout_at = 0;
425 ccfg->in_keep_alive = (c->keepalives > 0);
426 INIT_STAGE(cfg, ccfg, header);
427 }
428
reqtimeout_before_body(request_rec * r)429 static int reqtimeout_before_body(request_rec *r)
430 {
431 reqtimeout_srv_cfg *cfg;
432 reqtimeout_con_cfg *ccfg =
433 ap_get_module_config(r->connection->conn_config, &reqtimeout_module);
434
435 if (ccfg == NULL) {
436 /* not configured for this connection */
437 return OK;
438 }
439 cfg = ap_get_module_config(r->server->module_config,
440 &reqtimeout_module);
441 AP_DEBUG_ASSERT(cfg != NULL);
442
443 ccfg->type = "body";
444 ccfg->timeout_at = 0;
445 ccfg->max_timeout_at = 0;
446 if (r->method_number == M_CONNECT) {
447 /* disabled for a CONNECT request */
448 ccfg->cur_stage.timeout = 0;
449 }
450 else {
451 INIT_STAGE(cfg, ccfg, body);
452 }
453 return OK;
454 }
455
456 #define UNSET_STAGE(cfg, stage) do { \
457 cfg->stage.timeout = UNSET; \
458 cfg->stage.max_timeout = UNSET; \
459 cfg->stage.min_rate = UNSET; \
460 } while (0)
461
reqtimeout_create_srv_config(apr_pool_t * p,server_rec * s)462 static void *reqtimeout_create_srv_config(apr_pool_t *p, server_rec *s)
463 {
464 reqtimeout_srv_cfg *cfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg));
465
466 UNSET_STAGE(cfg, handshake);
467 UNSET_STAGE(cfg, header);
468 UNSET_STAGE(cfg, body);
469
470 return cfg;
471 }
472
473 #define MERGE_INT(cfg, base, add, val) \
474 cfg->val = (add->val == UNSET) ? base->val : add->val
475 #define MERGE_STAGE(cfg, base, add, stage) do { \
476 MERGE_INT(cfg, base, add, stage.timeout); \
477 MERGE_INT(cfg, base, add, stage.max_timeout); \
478 MERGE_INT(cfg, base, add, stage.min_rate); \
479 cfg->stage.rate_factor = (cfg->stage.min_rate == UNSET) \
480 ? base->stage.rate_factor \
481 : add->stage.rate_factor; \
482 } while (0)
483
reqtimeout_merge_srv_config(apr_pool_t * p,void * base_,void * add_)484 static void *reqtimeout_merge_srv_config(apr_pool_t *p, void *base_, void *add_)
485 {
486 reqtimeout_srv_cfg *base = base_;
487 reqtimeout_srv_cfg *add = add_;
488 reqtimeout_srv_cfg *cfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg));
489
490 MERGE_STAGE(cfg, base, add, handshake);
491 MERGE_STAGE(cfg, base, add, header);
492 MERGE_STAGE(cfg, base, add, body);
493
494 return cfg;
495 }
496
parse_int(apr_pool_t * p,const char * arg,int * val)497 static const char *parse_int(apr_pool_t *p, const char *arg, int *val)
498 {
499 char *endptr;
500 *val = strtol(arg, &endptr, 10);
501
502 if (arg == endptr) {
503 return apr_psprintf(p, "Value '%s' not numerical", endptr);
504 }
505 if (*endptr != '\0') {
506 return apr_psprintf(p, "Cannot parse '%s'", endptr);
507 }
508 if (*val < 0) {
509 return "Value must be non-negative";
510 }
511 return NULL;
512 }
513
set_reqtimeout_param(reqtimeout_srv_cfg * conf,apr_pool_t * p,const char * key,const char * val)514 static const char *set_reqtimeout_param(reqtimeout_srv_cfg *conf,
515 apr_pool_t *p,
516 const char *key,
517 const char *val)
518 {
519 const char *ret = NULL;
520 char *rate_str = NULL, *initial_str, *max_str = NULL;
521 reqtimeout_stage_t *stage;
522
523 if (!strcasecmp(key, "handshake")) {
524 stage = &conf->handshake;
525 }
526 else if (!strcasecmp(key, "header")) {
527 stage = &conf->header;
528 }
529 else if (!strcasecmp(key, "body")) {
530 stage = &conf->body;
531 }
532 else {
533 return "Unknown RequestReadTimeout parameter";
534 }
535
536 memset(stage, 0, sizeof(*stage));
537
538 if ((rate_str = ap_strcasestr(val, ",minrate="))) {
539 initial_str = apr_pstrndup(p, val, rate_str - val);
540 rate_str += strlen(",minrate=");
541 ret = parse_int(p, rate_str, &stage->min_rate);
542 if (ret)
543 return ret;
544
545 if (stage->min_rate == 0)
546 return "Minimum data rate must be larger than 0";
547
548 if ((max_str = strchr(initial_str, '-'))) {
549 *max_str++ = '\0';
550 ret = parse_int(p, max_str, &stage->max_timeout);
551 if (ret)
552 return ret;
553 }
554
555 ret = parse_int(p, initial_str, &stage->timeout);
556 }
557 else {
558 if (ap_strchr_c(val, '-'))
559 return "Must set MinRate option if using timeout range";
560 ret = parse_int(p, val, &stage->timeout);
561 }
562 if (ret)
563 return ret;
564
565 if (stage->max_timeout && stage->timeout >= stage->max_timeout) {
566 return "Maximum timeout must be larger than initial timeout";
567 }
568
569 if (stage->min_rate) {
570 stage->rate_factor = apr_time_from_sec(1) / stage->min_rate;
571 }
572
573 return NULL;
574 }
575
set_reqtimeouts(cmd_parms * cmd,void * mconfig,const char * arg)576 static const char *set_reqtimeouts(cmd_parms *cmd, void *mconfig,
577 const char *arg)
578 {
579 reqtimeout_srv_cfg *conf =
580 ap_get_module_config(cmd->server->module_config,
581 &reqtimeout_module);
582
583 while (*arg) {
584 char *word, *val;
585 const char *err;
586
587 word = ap_getword_conf(cmd->temp_pool, &arg);
588 val = strchr(word, '=');
589 if (!val) {
590 return "Invalid RequestReadTimeout parameter. Parameter must be "
591 "in the form 'key=value'";
592 }
593 else
594 *val++ = '\0';
595
596 err = set_reqtimeout_param(conf, cmd->pool, word, val);
597
598 if (err)
599 return apr_psprintf(cmd->temp_pool, "RequestReadTimeout: %s=%s: %s",
600 word, val, err);
601 }
602
603 return NULL;
604
605 }
606
reqtimeout_hooks(apr_pool_t * pool)607 static void reqtimeout_hooks(apr_pool_t *pool)
608 {
609 /*
610 * mod_ssl is AP_FTYPE_CONNECTION + 5 and mod_reqtimeout needs to
611 * be called before mod_ssl for the handshake stage to catch SSL traffic.
612 */
613 ap_register_input_filter(reqtimeout_filter_name, reqtimeout_filter, NULL,
614 AP_FTYPE_CONNECTION + 8);
615
616 /*
617 * We need to pause timeout detection in between requests, for
618 * speculative and non-blocking reads, so between each outgoing EOR
619 * and the next pre_read_request call.
620 */
621 ap_register_output_filter(reqtimeout_filter_name, reqtimeout_eor, NULL,
622 AP_FTYPE_CONNECTION);
623
624 /*
625 * mod_reqtimeout needs to be called before ap_process_http_request (which
626 * is run at APR_HOOK_REALLY_LAST) but after all other protocol modules.
627 * This ensures that it only influences normal http connections and not
628 * e.g. mod_ftp. We still process it first though, for the handshake stage
629 * to work with/before mod_ssl, but since it's disabled by default it won't
630 * influence non-HTTP modules unless configured explicitly. Also, if
631 * mod_reqtimeout used the pre_connection hook, it would be inserted on
632 * mod_proxy's backend connections, and we don't want this.
633 */
634 ap_hook_process_connection(reqtimeout_init, NULL, NULL, APR_HOOK_FIRST);
635
636 ap_hook_pre_read_request(reqtimeout_before_header, NULL, NULL,
637 APR_HOOK_MIDDLE);
638 ap_hook_post_read_request(reqtimeout_before_body, NULL, NULL,
639 APR_HOOK_MIDDLE);
640
641 #if MRT_DEFAULT_handshake_MIN_RATE
642 default_handshake_rate_factor = apr_time_from_sec(1) /
643 MRT_DEFAULT_handshake_MIN_RATE;
644 #endif
645 #if MRT_DEFAULT_header_MIN_RATE
646 default_header_rate_factor = apr_time_from_sec(1) /
647 MRT_DEFAULT_header_MIN_RATE;
648 #endif
649 #if MRT_DEFAULT_body_MIN_RATE
650 default_body_rate_factor = apr_time_from_sec(1) /
651 MRT_DEFAULT_body_MIN_RATE;
652 #endif
653 }
654
655 static const command_rec reqtimeout_cmds[] = {
656 AP_INIT_RAW_ARGS("RequestReadTimeout", set_reqtimeouts, NULL, RSRC_CONF,
657 "Set various timeout parameters for TLS handshake and/or "
658 "reading request headers and body"),
659 {NULL}
660 };
661
662 AP_DECLARE_MODULE(reqtimeout) = {
663 STANDARD20_MODULE_STUFF,
664 NULL, /* create per-dir config structures */
665 NULL, /* merge per-dir config structures */
666 reqtimeout_create_srv_config, /* create per-server config structures */
667 reqtimeout_merge_srv_config, /* merge per-server config structures */
668 reqtimeout_cmds, /* table of config file commands */
669 reqtimeout_hooks
670 };
671