View | Details | Raw Unified | Return to bug 61310
Collapse All | Expand All

(-)modules/filters/mod_reqtimeout.c (-52 / +99 lines)
Lines 38-51 module AP_MODULE_DECLARE_DATA reqtimeout_module; Link Here
38
38
39
typedef struct
39
typedef struct
40
{
40
{
41
    int header_timeout;     /* timeout for reading the req hdrs in secs */
41
    int timeout;            /* timeout in secs */
42
    int header_max_timeout; /* max timeout for req hdrs in secs */
42
    int max_timeout;        /* max timeout in secs */
43
    int header_min_rate;    /* min rate for reading req hdrs in bytes/s */
43
    int min_rate;           /* min rate in bytes/s */
44
    apr_time_t header_rate_factor;
44
    apr_time_t rate_factor;
45
    int body_timeout;       /* timeout for reading the req body in secs */
45
} reqtimeout_stage_t;
46
    int body_max_timeout;   /* max timeout for req body in secs */
46
47
    int body_min_rate;      /* min rate for reading req body in bytes/s */
47
typedef struct
48
    apr_time_t body_rate_factor;
48
{
49
    reqtimeout_stage_t handshake;   /* TLS handshake */
50
    reqtimeout_stage_t header;      /* Reading the HTTP header */
51
    reqtimeout_stage_t body;        /* Reading the body */
49
} reqtimeout_srv_cfg;
52
} reqtimeout_srv_cfg;
50
53
51
/* this struct is used both as conn_config and as filter context */
54
/* this struct is used both as conn_config and as filter context */
Lines 56-61 typedef struct Link Here
56
    int min_rate;
59
    int min_rate;
57
    int new_timeout;
60
    int new_timeout;
58
    int new_max_timeout;
61
    int new_max_timeout;
62
    int in_handshake;
59
    int in_keep_alive;
63
    int in_keep_alive;
60
    char *type;
64
    char *type;
61
    apr_socket_t *socket;
65
    apr_socket_t *socket;
Lines 177-182 static apr_status_t reqtimeout_filter(ap_filter_t Link Here
177
    apr_interval_time_t saved_sock_timeout = UNSET;
181
    apr_interval_time_t saved_sock_timeout = UNSET;
178
    reqtimeout_con_cfg *ccfg = f->ctx;
182
    reqtimeout_con_cfg *ccfg = f->ctx;
179
183
184
    if (ccfg->in_handshake < 0) {
185
        return ap_get_brigade(f->next, bb, mode, block, readbytes);
186
    }
187
180
    if (ccfg->in_keep_alive) {
188
    if (ccfg->in_keep_alive) {
181
        /* For this read[_request line()], wait for the first byte using the
189
        /* For this read[_request line()], wait for the first byte using the
182
         * normal keep-alive timeout (hence don't take this expected idle time
190
         * normal keep-alive timeout (hence don't take this expected idle time
Lines 358-364 static int reqtimeout_init(conn_rec *c) Link Here
358
    cfg = ap_get_module_config(c->base_server->module_config,
366
    cfg = ap_get_module_config(c->base_server->module_config,
359
                               &reqtimeout_module);
367
                               &reqtimeout_module);
360
    AP_DEBUG_ASSERT(cfg != NULL);
368
    AP_DEBUG_ASSERT(cfg != NULL);
361
    if (cfg->header_timeout == 0 && cfg->body_timeout == 0) {
369
370
    if ((cfg->handshake.timeout == 0 || cfg->handshake.timeout == UNSET)
371
            && cfg->header.timeout == 0 && cfg->body.timeout == 0) {
362
        /* disabled for this vhost */
372
        /* disabled for this vhost */
363
        return DECLINED;
373
        return DECLINED;
364
    }
374
    }
Lines 369-374 static int reqtimeout_init(conn_rec *c) Link Here
369
        ap_set_module_config(c->conn_config, &reqtimeout_module, ccfg);
379
        ap_set_module_config(c->conn_config, &reqtimeout_module, ccfg);
370
        ap_add_output_filter(reqtimeout_filter_name, ccfg, NULL, c);
380
        ap_add_output_filter(reqtimeout_filter_name, ccfg, NULL, c);
371
        ap_add_input_filter(reqtimeout_filter_name, ccfg, NULL, c);
381
        ap_add_input_filter(reqtimeout_filter_name, ccfg, NULL, c);
382
        if (cfg->handshake.timeout > 0) {
383
            ccfg->new_timeout     = cfg->handshake.timeout;
384
            ccfg->new_max_timeout = cfg->handshake.max_timeout;
385
            ccfg->min_rate        = cfg->handshake.min_rate;
386
            ccfg->rate_factor     = cfg->handshake.rate_factor;
387
            ccfg->type            = "handshake";
388
            ccfg->in_handshake    = +1;
389
        }
390
        else {
391
            ccfg->in_handshake    = -1;
392
        }
372
    }
393
    }
373
394
374
    /* we are not handling the connection, we just do initialization */
395
    /* we are not handling the connection, we just do initialization */
Lines 396-407 static void reqtimeout_before_header(request_rec * Link Here
396
    ccfg->timeout_at = 0;
417
    ccfg->timeout_at = 0;
397
    ccfg->max_timeout_at = 0;
418
    ccfg->max_timeout_at = 0;
398
    ccfg->in_keep_alive = (c->keepalives > 0);
419
    ccfg->in_keep_alive = (c->keepalives > 0);
420
    ccfg->in_handshake = 0;
399
    ccfg->type = "header";
421
    ccfg->type = "header";
400
    if (cfg->header_timeout != UNSET) {
422
    if (cfg->header.timeout != UNSET) {
401
        ccfg->new_timeout     = cfg->header_timeout;
423
        ccfg->new_timeout     = cfg->header.timeout;
402
        ccfg->new_max_timeout = cfg->header_max_timeout;
424
        ccfg->new_max_timeout = cfg->header.max_timeout;
403
        ccfg->min_rate        = cfg->header_min_rate;
425
        ccfg->min_rate        = cfg->header.min_rate;
404
        ccfg->rate_factor     = cfg->header_rate_factor;
426
        ccfg->rate_factor     = cfg->header.rate_factor;
405
    }
427
    }
406
    else {
428
    else {
407
        ccfg->new_timeout     = MRT_DEFAULT_HEADER_TIMEOUT;
429
        ccfg->new_timeout     = MRT_DEFAULT_HEADER_TIMEOUT;
Lines 432-442 static int reqtimeout_before_body(request_rec *r) Link Here
432
        /* disabled for a CONNECT request */
454
        /* disabled for a CONNECT request */
433
        ccfg->new_timeout     = 0;
455
        ccfg->new_timeout     = 0;
434
    }
456
    }
435
    else if (cfg->body_timeout != UNSET) {
457
    else if (cfg->body.timeout != UNSET) {
436
        ccfg->new_timeout     = cfg->body_timeout;
458
        ccfg->new_timeout     = cfg->body.timeout;
437
        ccfg->new_max_timeout = cfg->body_max_timeout;
459
        ccfg->new_max_timeout = cfg->body.max_timeout;
438
        ccfg->min_rate        = cfg->body_min_rate;
460
        ccfg->min_rate        = cfg->body.min_rate;
439
        ccfg->rate_factor     = cfg->body_rate_factor;
461
        ccfg->rate_factor     = cfg->body.rate_factor;
440
    }
462
    }
441
    else {
463
    else {
442
        ccfg->new_timeout     = MRT_DEFAULT_BODY_TIMEOUT;
464
        ccfg->new_timeout     = MRT_DEFAULT_BODY_TIMEOUT;
Lines 451-462 static void *reqtimeout_create_srv_config(apr_pool Link Here
451
{
473
{
452
    reqtimeout_srv_cfg *cfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg));
474
    reqtimeout_srv_cfg *cfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg));
453
475
454
    cfg->header_timeout = UNSET;
476
    cfg->handshake.timeout = UNSET;
455
    cfg->header_max_timeout = UNSET;
477
    cfg->handshake.max_timeout = UNSET;
456
    cfg->header_min_rate = UNSET;
478
    cfg->handshake.min_rate = UNSET;
457
    cfg->body_timeout = UNSET;
479
    cfg->header.timeout = UNSET;
458
    cfg->body_max_timeout = UNSET;
480
    cfg->header.max_timeout = UNSET;
459
    cfg->body_min_rate = UNSET;
481
    cfg->header.min_rate = UNSET;
482
    cfg->body.timeout = UNSET;
483
    cfg->body.max_timeout = UNSET;
484
    cfg->body.min_rate = UNSET;
460
485
461
    return cfg;
486
    return cfg;
462
}
487
}
Lines 468-484 static void *reqtimeout_merge_srv_config(apr_pool_ Link Here
468
    reqtimeout_srv_cfg *add  = add_;
493
    reqtimeout_srv_cfg *add  = add_;
469
    reqtimeout_srv_cfg *cfg  = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg));
494
    reqtimeout_srv_cfg *cfg  = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg));
470
495
471
    MERGE_INT(cfg, base, add, header_timeout);
496
    MERGE_INT(cfg, base, add, handshake.timeout);
472
    MERGE_INT(cfg, base, add, header_max_timeout);
497
    MERGE_INT(cfg, base, add, handshake.max_timeout);
473
    MERGE_INT(cfg, base, add, header_min_rate);
498
    MERGE_INT(cfg, base, add, handshake.min_rate);
474
    MERGE_INT(cfg, base, add, body_timeout);
499
    MERGE_INT(cfg, base, add, header.timeout);
475
    MERGE_INT(cfg, base, add, body_max_timeout);
500
    MERGE_INT(cfg, base, add, header.max_timeout);
476
    MERGE_INT(cfg, base, add, body_min_rate);
501
    MERGE_INT(cfg, base, add, header.min_rate);
502
    MERGE_INT(cfg, base, add, body.timeout);
503
    MERGE_INT(cfg, base, add, body.max_timeout);
504
    MERGE_INT(cfg, base, add, body.min_rate);
477
505
478
    cfg->header_rate_factor = (cfg->header_min_rate == UNSET) ?
506
    cfg->handshake.rate_factor = (cfg->handshake.min_rate == UNSET)
479
                              base->header_rate_factor : add->header_rate_factor;
507
                               ?  base->handshake.rate_factor
480
    cfg->body_rate_factor = (cfg->body_min_rate == UNSET) ?
508
                               : add->handshake.rate_factor;
481
                            base->body_rate_factor : add->body_rate_factor;
509
    cfg->header.rate_factor = (cfg->header.min_rate == UNSET)
510
                            ?  base->header.rate_factor
511
                            : add->header.rate_factor;
512
    cfg->body.rate_factor = (cfg->body.min_rate == UNSET)
513
                          ?  base->body.rate_factor
514
                          : add->body.rate_factor;
482
    return cfg;
515
    return cfg;
483
}
516
}
484
517
Lines 507-515 static const char *set_reqtimeout_param(reqtimeout Link Here
507
    const char *ret = NULL;
540
    const char *ret = NULL;
508
    char *rate_str = NULL, *initial_str, *max_str = NULL;
541
    char *rate_str = NULL, *initial_str, *max_str = NULL;
509
    int rate = 0, initial = 0, max = 0;
542
    int rate = 0, initial = 0, max = 0;
510
    enum { PARAM_HEADER, PARAM_BODY } type;
543
    enum { PARAM_HANDSHAKE, PARAM_HEADER, PARAM_BODY } type;
511
544
512
    if (!strcasecmp(key, "header")) {
545
    if (!strcasecmp(key, "handshake")) {
546
        type = PARAM_HANDSHAKE;
547
    }
548
    else if (!strcasecmp(key, "header")) {
513
        type = PARAM_HEADER;
549
        type = PARAM_HEADER;
514
    }
550
    }
515
    else if (!strcasecmp(key, "body")) {
551
    else if (!strcasecmp(key, "body")) {
Lines 551-571 static const char *set_reqtimeout_param(reqtimeout Link Here
551
        return "Maximum timeout must be larger than initial timeout";
587
        return "Maximum timeout must be larger than initial timeout";
552
    }
588
    }
553
589
554
    if (type == PARAM_HEADER) {
590
    switch (type) {
555
        conf->header_timeout = initial;
591
    case PARAM_HANDSHAKE:
556
        conf->header_max_timeout = max;
592
        conf->handshake.timeout = initial;
557
        conf->header_min_rate = rate;
593
        conf->handshake.max_timeout = max;
594
        conf->handshake.min_rate = rate;
558
        if (rate)
595
        if (rate)
559
            conf->header_rate_factor = apr_time_from_sec(1) / rate;
596
            conf->handshake.rate_factor = apr_time_from_sec(1) / rate;
560
    }
597
        break;
561
    else {
598
562
        conf->body_timeout = initial;
599
    case PARAM_HEADER:
563
        conf->body_max_timeout = max;
600
        conf->header.timeout = initial;
564
        conf->body_min_rate = rate;
601
        conf->header.max_timeout = max;
602
        conf->header.min_rate = rate;
565
        if (rate)
603
        if (rate)
566
            conf->body_rate_factor = apr_time_from_sec(1) / rate;
604
            conf->header.rate_factor = apr_time_from_sec(1) / rate;
605
        break;
606
607
    default:
608
        conf->body.timeout = initial;
609
        conf->body.max_timeout = max;
610
        conf->body.min_rate = rate;
611
        if (rate)
612
            conf->body.rate_factor = apr_time_from_sec(1) / rate;
613
        break;
567
    }
614
    }
568
    return ret;
615
    return NULL;
569
}
616
}
570
617
571
static const char *set_reqtimeouts(cmd_parms *cmd, void *mconfig,
618
static const char *set_reqtimeouts(cmd_parms *cmd, void *mconfig,
Lines 624-630 static void reqtimeout_hooks(apr_pool_t *pool) Link Here
624
     * e.g. mod_ftp. Also, if mod_reqtimeout used the pre_connection hook, it
671
     * e.g. mod_ftp. Also, if mod_reqtimeout used the pre_connection hook, it
625
     * would be inserted on mod_proxy's backend connections.
672
     * would be inserted on mod_proxy's backend connections.
626
     */
673
     */
627
    ap_hook_process_connection(reqtimeout_init, NULL, NULL, APR_HOOK_LAST);
674
    ap_hook_process_connection(reqtimeout_init, NULL, NULL, APR_HOOK_FIRST);
628
675
629
    ap_hook_pre_read_request(reqtimeout_before_header, NULL, NULL,
676
    ap_hook_pre_read_request(reqtimeout_before_header, NULL, NULL,
630
                             APR_HOOK_MIDDLE);
677
                             APR_HOOK_MIDDLE);
Lines 641-648 static void reqtimeout_hooks(apr_pool_t *pool) Link Here
641
688
642
static const command_rec reqtimeout_cmds[] = {
689
static const command_rec reqtimeout_cmds[] = {
643
    AP_INIT_RAW_ARGS("RequestReadTimeout", set_reqtimeouts, NULL, RSRC_CONF,
690
    AP_INIT_RAW_ARGS("RequestReadTimeout", set_reqtimeouts, NULL, RSRC_CONF,
644
                     "Set various timeout parameters for reading request "
691
                     "Set various timeout parameters for TLS handshake or "
645
                     "headers and body"),
692
                     "reading request headers and body"),
646
    {NULL}
693
    {NULL}
647
};
694
};
648
695

Return to bug 61310