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