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

(-)modules/filters/mod_reqtimeout.c (-81 / +171 lines)
Lines 48-53 Link Here
48
    apr_time_t body_rate_factor;
48
    apr_time_t body_rate_factor;
49
} reqtimeout_srv_cfg;
49
} reqtimeout_srv_cfg;
50
50
51
typedef struct
52
{
53
    int body_timeout;       /* timeout for reading the req body in secs */
54
    int body_max_timeout;   /* max timeout for req body in secs */
55
    int body_min_rate;      /* min rate for reading req body in bytes/s */
56
    apr_time_t body_rate_factor;
57
} reqtimeout_dir_cfg;
58
51
/* this struct is used both as conn_config and as filter context */
59
/* this struct is used both as conn_config and as filter context */
52
typedef struct
60
typedef struct
53
{
61
{
Lines 348-359 Link Here
348
static int reqtimeout_init(conn_rec *c)
356
static int reqtimeout_init(conn_rec *c)
349
{
357
{
350
    reqtimeout_con_cfg *ccfg;
358
    reqtimeout_con_cfg *ccfg;
351
    reqtimeout_srv_cfg *cfg;
359
    reqtimeout_srv_cfg *scfg;
352
360
353
    cfg = ap_get_module_config(c->base_server->module_config,
361
    scfg = ap_get_module_config(c->base_server->module_config,
354
                               &reqtimeout_module);
362
                               &reqtimeout_module);
355
    AP_DEBUG_ASSERT(cfg != NULL);
363
    AP_DEBUG_ASSERT(scfg != NULL);
356
    if (cfg->header_timeout == 0 && cfg->body_timeout == 0) {
364
    if (scfg->header_timeout == 0 && scfg->body_timeout == 0) {
357
        /* disabled for this vhost */
365
        /* disabled for this vhost */
358
        return DECLINED;
366
        return DECLINED;
359
    }
367
    }
Lines 370-380 Link Here
370
    }
378
    }
371
379
372
    ccfg->type = "header";
380
    ccfg->type = "header";
373
    if (cfg->header_timeout != UNSET) {
381
    if (scfg->header_timeout != UNSET) {
374
        ccfg->new_timeout     = cfg->header_timeout;
382
        ccfg->new_timeout     = scfg->header_timeout;
375
        ccfg->new_max_timeout = cfg->header_max_timeout;
383
        ccfg->new_max_timeout = scfg->header_max_timeout;
376
        ccfg->min_rate        = cfg->header_min_rate;
384
        ccfg->min_rate        = scfg->header_min_rate;
377
        ccfg->rate_factor     = cfg->header_rate_factor;
385
        ccfg->rate_factor     = scfg->header_rate_factor;
378
    }
386
    }
379
    else {
387
    else {
380
        ccfg->new_timeout     = MRT_DEFAULT_HEADER_TIMEOUT;
388
        ccfg->new_timeout     = MRT_DEFAULT_HEADER_TIMEOUT;
Lines 389-415 Link Here
389
397
390
static int reqtimeout_after_headers(request_rec *r)
398
static int reqtimeout_after_headers(request_rec *r)
391
{
399
{
392
    reqtimeout_srv_cfg *cfg;
400
    reqtimeout_srv_cfg *scfg;
393
    reqtimeout_con_cfg *ccfg =
401
    reqtimeout_con_cfg *ccfg =
394
        ap_get_module_config(r->connection->conn_config, &reqtimeout_module);
402
        ap_get_module_config(r->connection->conn_config, &reqtimeout_module);
403
    reqtimeout_dir_cfg *dcfg=
404
        ap_get_module_config(r->per_dir_config, &reqtimeout_module);
395
405
396
    if (ccfg == NULL || r->method_number == M_CONNECT) {
406
    if (ccfg == NULL || r->method_number == M_CONNECT) {
397
        /* either disabled for this connection or a CONNECT request */
407
        /* either disabled for this connection or a CONNECT request */
398
        return OK;
408
        return OK;
399
    }
409
    }
400
    cfg = ap_get_module_config(r->connection->base_server->module_config,
410
    scfg = ap_get_module_config(r->connection->base_server->module_config,
401
                               &reqtimeout_module);
411
                                &reqtimeout_module);
402
    AP_DEBUG_ASSERT(cfg != NULL);
412
    AP_DEBUG_ASSERT(scfg != NULL);
403
413
404
    ccfg->timeout_at = 0;
414
    ccfg->timeout_at = 0;
405
    ccfg->max_timeout_at = 0;
415
    ccfg->max_timeout_at = 0;
406
    ccfg->type = "body";
416
    ccfg->type = "body";
407
    if (cfg->body_timeout != UNSET) {
417
408
        ccfg->new_timeout     = cfg->body_timeout;
418
    if (dcfg->body_timeout != UNSET) {
409
        ccfg->new_max_timeout = cfg->body_max_timeout;
419
        ccfg->new_timeout     = dcfg->body_timeout;
410
        ccfg->min_rate        = cfg->body_min_rate;
420
        ccfg->new_max_timeout = dcfg->body_max_timeout;
411
        ccfg->rate_factor     = cfg->body_rate_factor;
421
        ccfg->min_rate        = dcfg->body_min_rate;
422
        ccfg->rate_factor     = dcfg->body_rate_factor;
412
    }
423
    }
424
    else if (scfg->body_timeout != UNSET) {
425
        ccfg->new_timeout     = scfg->body_timeout;
426
        ccfg->new_max_timeout = scfg->body_max_timeout;
427
        ccfg->min_rate        = scfg->body_min_rate;
428
        ccfg->rate_factor     = scfg->body_rate_factor;
429
    }
413
    else {
430
    else {
414
        ccfg->new_timeout     = MRT_DEFAULT_BODY_TIMEOUT;
431
        ccfg->new_timeout     = MRT_DEFAULT_BODY_TIMEOUT;
415
        ccfg->new_max_timeout = MRT_DEFAULT_BODY_MAX_TIMEOUT;
432
        ccfg->new_max_timeout = MRT_DEFAULT_BODY_MAX_TIMEOUT;
Lines 421-427 Link Here
421
438
422
static int reqtimeout_after_body(request_rec *r)
439
static int reqtimeout_after_body(request_rec *r)
423
{
440
{
424
    reqtimeout_srv_cfg *cfg;
441
    reqtimeout_srv_cfg *scfg;
425
    reqtimeout_con_cfg *ccfg =
442
    reqtimeout_con_cfg *ccfg =
426
        ap_get_module_config(r->connection->conn_config, &reqtimeout_module);
443
        ap_get_module_config(r->connection->conn_config, &reqtimeout_module);
427
444
Lines 430-448 Link Here
430
        return OK;
447
        return OK;
431
    }
448
    }
432
449
433
    cfg = ap_get_module_config(r->connection->base_server->module_config,
450
    scfg = ap_get_module_config(r->connection->base_server->module_config,
434
                               &reqtimeout_module);
451
                               &reqtimeout_module);
435
    AP_DEBUG_ASSERT(cfg != NULL);
452
    AP_DEBUG_ASSERT(scfg != NULL);
436
453
437
    ccfg->timeout_at = 0;
454
    ccfg->timeout_at = 0;
438
    ccfg->max_timeout_at = 0;
455
    ccfg->max_timeout_at = 0;
439
    ccfg->in_keep_alive = 1;
456
    ccfg->in_keep_alive = 1;
440
    ccfg->type = "header";
457
    ccfg->type = "header";
441
    if (ccfg->new_timeout != UNSET) {
458
    if (ccfg->new_timeout != UNSET) {
442
        ccfg->new_timeout     = cfg->header_timeout;
459
        ccfg->new_timeout     = scfg->header_timeout;
443
        ccfg->new_max_timeout = cfg->header_max_timeout;
460
        ccfg->new_max_timeout = scfg->header_max_timeout;
444
        ccfg->min_rate        = cfg->header_min_rate;
461
        ccfg->min_rate        = scfg->header_min_rate;
445
        ccfg->rate_factor     = cfg->header_rate_factor;
462
        ccfg->rate_factor     = scfg->header_rate_factor;
446
    }
463
    }
447
    else {
464
    else {
448
        ccfg->new_timeout     = MRT_DEFAULT_HEADER_TIMEOUT;
465
        ccfg->new_timeout     = MRT_DEFAULT_HEADER_TIMEOUT;
Lines 456-494 Link Here
456
473
457
static void *reqtimeout_create_srv_config(apr_pool_t *p, server_rec *s)
474
static void *reqtimeout_create_srv_config(apr_pool_t *p, server_rec *s)
458
{
475
{
459
    reqtimeout_srv_cfg *cfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg));
476
    reqtimeout_srv_cfg *scfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg));
460
477
461
    cfg->header_timeout = UNSET;
478
    scfg->header_timeout = UNSET;
462
    cfg->header_max_timeout = UNSET;
479
    scfg->header_max_timeout = UNSET;
463
    cfg->header_min_rate = UNSET;
480
    scfg->header_min_rate = UNSET;
464
    cfg->body_timeout = UNSET;
481
    scfg->body_timeout = UNSET;
465
    cfg->body_max_timeout = UNSET;
482
    scfg->body_max_timeout = UNSET;
466
    cfg->body_min_rate = UNSET;
483
    scfg->body_min_rate = UNSET;
467
484
468
    return cfg;
485
    return scfg;
469
}
486
}
470
487
488
static void *reqtimeout_create_dir_config(apr_pool_t *p, char *dir)
489
{
490
    reqtimeout_dir_cfg *dcfg = apr_pcalloc(p, sizeof(reqtimeout_dir_cfg));
491
492
    dcfg->body_timeout = UNSET;
493
    dcfg->body_max_timeout = UNSET;
494
    dcfg->body_min_rate = UNSET;
495
496
    return dcfg;
497
}
498
471
#define MERGE_INT(cfg, b, a, val) cfg->val = (a->val == UNSET) ? b->val : a->val;
499
#define MERGE_INT(cfg, b, a, val) cfg->val = (a->val == UNSET) ? b->val : a->val;
472
static void *reqtimeout_merge_srv_config(apr_pool_t *p, void *base_, void *add_)
500
static void *reqtimeout_merge_srv_config(apr_pool_t *p, void *base_, void *add_)
473
{
501
{
474
    reqtimeout_srv_cfg *base = base_;
502
    reqtimeout_srv_cfg *base = base_;
475
    reqtimeout_srv_cfg *add  = add_;
503
    reqtimeout_srv_cfg *add  = add_;
476
    reqtimeout_srv_cfg *cfg  = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg));
504
    reqtimeout_srv_cfg *scfg  = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg));
477
505
478
    MERGE_INT(cfg, base, add, header_timeout);
506
    MERGE_INT(scfg, base, add, header_timeout);
479
    MERGE_INT(cfg, base, add, header_max_timeout);
507
    MERGE_INT(scfg, base, add, header_max_timeout);
480
    MERGE_INT(cfg, base, add, header_min_rate);
508
    MERGE_INT(scfg, base, add, header_min_rate);
481
    MERGE_INT(cfg, base, add, body_timeout);
509
    MERGE_INT(scfg, base, add, body_timeout);
482
    MERGE_INT(cfg, base, add, body_max_timeout);
510
    MERGE_INT(scfg, base, add, body_max_timeout);
483
    MERGE_INT(cfg, base, add, body_min_rate);
511
    MERGE_INT(scfg, base, add, body_min_rate);
484
512
485
    cfg->header_rate_factor = (cfg->header_min_rate == UNSET) ?
513
    scfg->header_rate_factor = (scfg->header_min_rate == UNSET) ?
486
                              base->header_rate_factor : add->header_rate_factor;
514
                               base->header_rate_factor : add->header_rate_factor;
487
    cfg->body_rate_factor = (cfg->body_min_rate == UNSET) ?
515
    scfg->body_rate_factor = (scfg->body_min_rate == UNSET) ?
488
                            base->body_rate_factor : add->body_rate_factor;
516
                             base->body_rate_factor : add->body_rate_factor;
489
    return cfg;
517
    return scfg;
490
}
518
}
491
519
520
static void *reqtimeout_merge_dir_config(apr_pool_t *p, void *base_, void *add_)
521
{
522
    reqtimeout_dir_cfg *base = base_;
523
    reqtimeout_dir_cfg *add  = add_;
524
    reqtimeout_dir_cfg *dcfg  = apr_pcalloc(p, sizeof(reqtimeout_dir_cfg));
525
526
    MERGE_INT(dcfg, base, add, body_timeout);
527
    MERGE_INT(dcfg, base, add, body_max_timeout);
528
    MERGE_INT(dcfg, base, add, body_min_rate);
529
    
530
    dcfg->body_rate_factor = (dcfg->body_min_rate == UNSET) ?
531
                             base->body_rate_factor : add->body_rate_factor;
532
533
    return dcfg;
534
}
535
492
static const char *parse_int(apr_pool_t *p, const char *arg, int *val) {
536
static const char *parse_int(apr_pool_t *p, const char *arg, int *val) {
493
    char *endptr;
537
    char *endptr;
494
    *val = strtol(arg, &endptr, 10);
538
    *val = strtol(arg, &endptr, 10);
Lines 505-534 Link Here
505
    return NULL;
549
    return NULL;
506
}
550
}
507
551
508
static const char *set_reqtimeout_param(reqtimeout_srv_cfg *conf,
552
static const char *parse_setting(apr_pool_t *p, const char *val, int *initial,
509
                                      apr_pool_t *p,
553
                                 int *max, int *rate)
510
                                      const char *key,
511
                                      const char *val)
512
{
554
{
513
    const char *ret = NULL;
555
    const char *ret = NULL;
514
    char *rate_str = NULL, *initial_str, *max_str = NULL;
556
    char *rate_str = NULL, *initial_str, *max_str = NULL;
515
    int rate = 0, initial = 0, max = 0;
516
    enum { PARAM_HEADER, PARAM_BODY } type;
517
557
518
    if (!strcasecmp(key, "header")) {
519
        type = PARAM_HEADER;
520
    }
521
    else if (!strcasecmp(key, "body")) {
522
        type = PARAM_BODY;
523
    }
524
    else {
525
        return "Unknown RequestReadTimeout parameter";
526
    }
527
528
    if ((rate_str = ap_strcasestr(val, ",minrate="))) {
558
    if ((rate_str = ap_strcasestr(val, ",minrate="))) {
529
        initial_str = apr_pstrndup(p, val, rate_str - val);
559
        initial_str = apr_pstrndup(p, val, rate_str - val);
530
        rate_str += strlen(",minrate=");
560
        rate_str += strlen(",minrate=");
531
        ret = parse_int(p, rate_str, &rate);
561
        ret = parse_int(p, rate_str, rate);
532
        if (ret)
562
        if (ret)
533
            return ret;
563
            return ret;
534
564
Lines 537-583 Link Here
537
567
538
        if ((max_str = strchr(initial_str, '-'))) {
568
        if ((max_str = strchr(initial_str, '-'))) {
539
            *max_str++ = '\0';
569
            *max_str++ = '\0';
540
            ret = parse_int(p, max_str, &max);
570
            ret = parse_int(p, max_str, max);
541
            if (ret)
571
            if (ret)
542
                return ret;
572
                return ret;
543
        }
573
        }
544
574
545
        ret = parse_int(p, initial_str, &initial);
575
        ret = parse_int(p, initial_str, initial);
546
    }
576
    }
547
    else {
577
    else {
548
        if (ap_strchr_c(val, '-'))
578
        if (ap_strchr_c(val, '-'))
549
            return "Must set MinRate option if using timeout range";
579
            return "Must set MinRate option if using timeout range";
550
        ret = parse_int(p, val, &initial);
580
        ret = parse_int(p, val, initial);
551
    }
581
    }
552
582
553
    if (ret)
583
    if (ret)
554
        return ret;
584
        return ret;
555
585
556
    if (max && initial >= max) {
586
    if (*max && *initial >= *max) {
557
        return "Maximum timeout must be larger than initial timeout";
587
        return "Maximum timeout must be larger than initial timeout";
558
    }
588
    }
559
589
590
    return NULL;
591
}
592
593
static const char *set_reqtimeout_srv_param(reqtimeout_srv_cfg *scfg,
594
                                            apr_pool_t *p,
595
                                            const char *key,
596
                                            const char *val)
597
{
598
    const char *ret = NULL;
599
    int rate = 0, initial = 0, max = 0;
600
    enum { PARAM_HEADER, PARAM_BODY } type;
601
602
    if (!strcasecmp(key, "header")) {
603
        type = PARAM_HEADER;
604
    }
605
    else if (!strcasecmp(key, "body")) {
606
        type = PARAM_BODY;
607
    }
608
    else {
609
        return "Unknown RequestReadTimeout parameter";
610
    }
611
612
    ret = parse_setting(p, val, &initial, &max, &rate);
613
    if (ret)
614
        return ret;
615
560
    if (type == PARAM_HEADER) {
616
    if (type == PARAM_HEADER) {
561
        conf->header_timeout = initial;
617
        scfg->header_timeout = initial;
562
        conf->header_max_timeout = max;
618
        scfg->header_max_timeout = max;
563
        conf->header_min_rate = rate;
619
        scfg->header_min_rate = rate;
564
        if (rate)
620
        if (rate)
565
            conf->header_rate_factor = apr_time_from_sec(1) / rate;
621
            scfg->header_rate_factor = apr_time_from_sec(1) / rate;
566
    }
622
    }
567
    else {
623
    else {
568
        conf->body_timeout = initial;
624
        scfg->body_timeout = initial;
569
        conf->body_max_timeout = max;
625
        scfg->body_max_timeout = max;
570
        conf->body_min_rate = rate;
626
        scfg->body_min_rate = rate;
571
        if (rate)
627
        if (rate)
572
            conf->body_rate_factor = apr_time_from_sec(1) / rate;
628
            scfg->body_rate_factor = apr_time_from_sec(1) / rate;
573
    }
629
    }
630
574
    return ret;
631
    return ret;
575
}
632
}
576
633
634
static const char *set_reqtimeout_dir_param(reqtimeout_dir_cfg *dcfg,
635
                                            apr_pool_t *p,
636
                                            const char *key,
637
                                            const char *val)
638
{
639
    const char *ret = NULL;
640
    int rate = 0, initial = 0, max = 0;
641
642
    if (!strcasecmp(key, "header")) {
643
        return "Header timeout can not be changed within a location or directory";
644
    }
645
    else if (strcasecmp(key, "body")) {
646
        return "Unknown RequestReadTimeout parameter";
647
    }
648
649
    ret = parse_setting(p, val, &initial, &max, &rate);
650
    if (ret)
651
        return ret;
652
653
    dcfg->body_timeout = initial;
654
    dcfg->body_max_timeout = max;
655
    dcfg->body_min_rate = rate;
656
    if (rate)
657
        dcfg->body_rate_factor = apr_time_from_sec(1) / rate;
658
659
    return ret;
660
}
661
577
static const char *set_reqtimeouts(cmd_parms *cmd, void *mconfig,
662
static const char *set_reqtimeouts(cmd_parms *cmd, void *mconfig,
578
                                   const char *arg)
663
                                   const char *arg)
579
{
664
{
580
    reqtimeout_srv_cfg *conf =
665
    reqtimeout_srv_cfg *scfg =
581
    ap_get_module_config(cmd->server->module_config,
666
    ap_get_module_config(cmd->server->module_config,
582
                         &reqtimeout_module);
667
                         &reqtimeout_module);
583
668
Lines 594-600 Link Here
594
        else
679
        else
595
            *val++ = '\0';
680
            *val++ = '\0';
596
681
597
        err = set_reqtimeout_param(conf, cmd->pool, word, val);
682
        if (cmd->path == NULL) {
683
            err = set_reqtimeout_srv_param(scfg, cmd->pool, word, val);
684
        }
685
        else {
686
            err = set_reqtimeout_dir_param(mconfig, cmd->pool, word, val);
687
        }
598
688
599
        if (err)
689
        if (err)
600
            return apr_psprintf(cmd->temp_pool, "RequestReadTimeout: %s=%s: %s",
690
            return apr_psprintf(cmd->temp_pool, "RequestReadTimeout: %s=%s: %s",
Lines 624-631 Link Here
624
     */
714
     */
625
    ap_hook_process_connection(reqtimeout_init, NULL, NULL, APR_HOOK_LAST);
715
    ap_hook_process_connection(reqtimeout_init, NULL, NULL, APR_HOOK_LAST);
626
716
627
    ap_hook_post_read_request(reqtimeout_after_headers, NULL, NULL,
717
    ap_hook_post_perdir_config(reqtimeout_after_headers, NULL, NULL,
628
                              APR_HOOK_MIDDLE);
718
                               APR_HOOK_MIDDLE);
629
    ap_hook_log_transaction(reqtimeout_after_body, NULL, NULL,
719
    ap_hook_log_transaction(reqtimeout_after_body, NULL, NULL,
630
                            APR_HOOK_MIDDLE);
720
                            APR_HOOK_MIDDLE);
631
721
Lines 638-644 Link Here
638
}
728
}
639
729
640
static const command_rec reqtimeout_cmds[] = {
730
static const command_rec reqtimeout_cmds[] = {
641
    AP_INIT_RAW_ARGS("RequestReadTimeout", set_reqtimeouts, NULL, RSRC_CONF,
731
    AP_INIT_RAW_ARGS("RequestReadTimeout", set_reqtimeouts, NULL, ACCESS_CONF|RSRC_CONF,
642
                     "Set various timeout parameters for reading request "
732
                     "Set various timeout parameters for reading request "
643
                     "headers and body"),
733
                     "headers and body"),
644
    {NULL}
734
    {NULL}
Lines 646-653 Link Here
646
736
647
AP_DECLARE_MODULE(reqtimeout) = {
737
AP_DECLARE_MODULE(reqtimeout) = {
648
    STANDARD20_MODULE_STUFF,
738
    STANDARD20_MODULE_STUFF,
649
    NULL,                           /* create per-dir config structures */
739
    reqtimeout_create_dir_config,   /* create per-dir config structures */
650
    NULL,                           /* merge  per-dir config structures */
740
    reqtimeout_merge_dir_config,    /* merge  per-dir config structures */
651
    reqtimeout_create_srv_config,   /* create per-server config structures */
741
    reqtimeout_create_srv_config,   /* create per-server config structures */
652
    reqtimeout_merge_srv_config,    /* merge per-server config structures */
742
    reqtimeout_merge_srv_config,    /* merge per-server config structures */
653
    reqtimeout_cmds,                /* table of config file commands */
743
    reqtimeout_cmds,                /* table of config file commands */

Return to bug 57439