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