"Fossies" - the Fresh Open Source Software Archive

Member "mod_http2-1.15.17/mod_http2/h2_config.c" (22 Feb 2021, 35903 Bytes) of package /linux/www/apache_httpd_modules/mod_http2-1.15.17.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "h2_config.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.15.16_vs_1.15.17.

    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 <assert.h>
   18 
   19 #include <apr_hash.h>
   20 #include <apr_lib.h>
   21 
   22 #include <httpd.h>
   23 #include <http_core.h>
   24 #include <http_config.h>
   25 #include <http_log.h>
   26 #include <http_vhost.h>
   27 
   28 #include <ap_mpm.h>
   29 
   30 #include <apr_strings.h>
   31 
   32 #include "h2.h"
   33 #include "h2_alt_svc.h"
   34 #include "h2_ctx.h"
   35 #include "h2_conn.h"
   36 #include "h2_config.h"
   37 #include "h2_h2.h"
   38 #include "h2_private.h"
   39 
   40 #define DEF_VAL     (-1)
   41 
   42 #define H2_CONFIG_GET(a, b, n) \
   43     (((a)->n == DEF_VAL)? (b) : (a))->n
   44 
   45 #define H2_CONFIG_SET(a, n, v) \
   46     ((a)->n = v)
   47 
   48 #define CONFIG_CMD_SET(cmd,dir,var,val) \
   49     h2_config_seti(((cmd)->path? (dir) : NULL), h2_config_sget((cmd)->server), var, val)
   50 
   51 #define CONFIG_CMD_SET64(cmd,dir,var,val) \
   52     h2_config_seti64(((cmd)->path? (dir) : NULL), h2_config_sget((cmd)->server), var, val)
   53 
   54 /* Apache httpd module configuration for h2. */
   55 typedef struct h2_config {
   56     const char *name;
   57     int h2_max_streams;           /* max concurrent # streams (http2) */
   58     int h2_window_size;           /* stream window size (http2) */
   59     int min_workers;              /* min # of worker threads/child */
   60     int max_workers;              /* max # of worker threads/child */
   61     int max_worker_idle_secs;     /* max # of idle seconds for worker */
   62     int stream_max_mem_size;      /* max # bytes held in memory/stream */
   63     apr_array_header_t *alt_svcs; /* h2_alt_svc specs for this server */
   64     int alt_svc_max_age;          /* seconds clients can rely on alt-svc info*/
   65     int serialize_headers;        /* Use serialized HTTP/1.1 headers for 
   66                                      processing, better compatibility */
   67     int h2_direct;                /* if mod_h2 is active directly */
   68     int modern_tls_only;          /* Accept only modern TLS in HTTP/2 connections */  
   69     int h2_upgrade;               /* Allow HTTP/1 upgrade to h2/h2c */
   70     apr_int64_t tls_warmup_size;  /* Amount of TLS data to send before going full write size */
   71     int tls_cooldown_secs;        /* Seconds of idle time before going back to small TLS records */
   72     int h2_push;                  /* if HTTP/2 server push is enabled */
   73     struct apr_hash_t *priorities;/* map of content-type to h2_priority records */
   74     
   75     int push_diary_size;          /* # of entries in push diary */
   76     int copy_files;               /* if files shall be copied vs setaside on output */
   77     apr_array_header_t *push_list;/* list of h2_push_res configurations */
   78     int early_hints;              /* support status code 103 */
   79     int padding_bits;
   80     int padding_always;
   81     int output_buffered;
   82 } h2_config;
   83 
   84 typedef struct h2_dir_config {
   85     const char *name;
   86     apr_array_header_t *alt_svcs; /* h2_alt_svc specs for this server */
   87     int alt_svc_max_age;          /* seconds clients can rely on alt-svc info*/
   88     int h2_upgrade;               /* Allow HTTP/1 upgrade to h2/h2c */
   89     int h2_push;                  /* if HTTP/2 server push is enabled */
   90     apr_array_header_t *push_list;/* list of h2_push_res configurations */
   91     int early_hints;              /* support status code 103 */
   92 } h2_dir_config;
   93 
   94 
   95 static h2_config defconf = {
   96     "default",
   97     100,                    /* max_streams */
   98     H2_INITIAL_WINDOW_SIZE, /* window_size */
   99     -1,                     /* min workers */
  100     -1,                     /* max workers */
  101     10 * 60,                /* max workers idle secs */
  102     32 * 1024,              /* stream max mem size */
  103     NULL,                   /* no alt-svcs */
  104     -1,                     /* alt-svc max age */
  105     0,                      /* serialize headers */
  106     -1,                     /* h2 direct mode */
  107     1,                      /* modern TLS only */
  108     -1,                     /* HTTP/1 Upgrade support */
  109     1024*1024,              /* TLS warmup size */
  110     1,                      /* TLS cooldown secs */
  111     1,                      /* HTTP/2 server push enabled */
  112     NULL,                   /* map of content-type to priorities */
  113     256,                    /* push diary size */
  114     0,                      /* copy files across threads */
  115     NULL,                   /* push list */
  116     0,                      /* early hints, http status 103 */
  117     0,                      /* padding bits */
  118     1,                      /* padding always */
  119     1,                      /* strean output buffered */
  120 };
  121 
  122 static h2_dir_config defdconf = {
  123     "default",
  124     NULL,                   /* no alt-svcs */
  125     -1,                     /* alt-svc max age */
  126     -1,                     /* HTTP/1 Upgrade support */
  127     -1,                     /* HTTP/2 server push enabled */
  128     NULL,                   /* push list */
  129     -1,                     /* early hints, http status 103 */
  130 };
  131 
  132 void h2_config_init(apr_pool_t *pool)
  133 {
  134     (void)pool;
  135 }
  136 
  137 void *h2_config_create_svr(apr_pool_t *pool, server_rec *s)
  138 {
  139     h2_config *conf = (h2_config *)apr_pcalloc(pool, sizeof(h2_config));
  140     char *name = apr_pstrcat(pool, "srv[", s->defn_name, "]", NULL);
  141     
  142     conf->name                 = name;
  143     conf->h2_max_streams       = DEF_VAL;
  144     conf->h2_window_size       = DEF_VAL;
  145     conf->min_workers          = DEF_VAL;
  146     conf->max_workers          = DEF_VAL;
  147     conf->max_worker_idle_secs = DEF_VAL;
  148     conf->stream_max_mem_size  = DEF_VAL;
  149     conf->alt_svc_max_age      = DEF_VAL;
  150     conf->serialize_headers    = DEF_VAL;
  151     conf->h2_direct            = DEF_VAL;
  152     conf->modern_tls_only      = DEF_VAL;
  153     conf->h2_upgrade           = DEF_VAL;
  154     conf->tls_warmup_size      = DEF_VAL;
  155     conf->tls_cooldown_secs    = DEF_VAL;
  156     conf->h2_push              = DEF_VAL;
  157     conf->priorities           = NULL;
  158     conf->push_diary_size      = DEF_VAL;
  159     conf->copy_files           = DEF_VAL;
  160     conf->push_list            = NULL;
  161     conf->early_hints          = DEF_VAL;
  162     conf->padding_bits         = DEF_VAL;
  163     conf->padding_always       = DEF_VAL;
  164     conf->output_buffered      = DEF_VAL;
  165     return conf;
  166 }
  167 
  168 static void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv)
  169 {
  170     h2_config *base = (h2_config *)basev;
  171     h2_config *add = (h2_config *)addv;
  172     h2_config *n = (h2_config *)apr_pcalloc(pool, sizeof(h2_config));
  173     char *name = apr_pstrcat(pool, "merged[", add->name, ", ", base->name, "]", NULL);
  174     n->name = name;
  175 
  176     n->h2_max_streams       = H2_CONFIG_GET(add, base, h2_max_streams);
  177     n->h2_window_size       = H2_CONFIG_GET(add, base, h2_window_size);
  178     n->min_workers          = H2_CONFIG_GET(add, base, min_workers);
  179     n->max_workers          = H2_CONFIG_GET(add, base, max_workers);
  180     n->max_worker_idle_secs = H2_CONFIG_GET(add, base, max_worker_idle_secs);
  181     n->stream_max_mem_size  = H2_CONFIG_GET(add, base, stream_max_mem_size);
  182     n->alt_svcs             = add->alt_svcs? add->alt_svcs : base->alt_svcs;
  183     n->alt_svc_max_age      = H2_CONFIG_GET(add, base, alt_svc_max_age);
  184     n->serialize_headers    = H2_CONFIG_GET(add, base, serialize_headers);
  185     n->h2_direct            = H2_CONFIG_GET(add, base, h2_direct);
  186     n->modern_tls_only      = H2_CONFIG_GET(add, base, modern_tls_only);
  187     n->h2_upgrade           = H2_CONFIG_GET(add, base, h2_upgrade);
  188     n->tls_warmup_size      = H2_CONFIG_GET(add, base, tls_warmup_size);
  189     n->tls_cooldown_secs    = H2_CONFIG_GET(add, base, tls_cooldown_secs);
  190     n->h2_push              = H2_CONFIG_GET(add, base, h2_push);
  191     if (add->priorities && base->priorities) {
  192         n->priorities       = apr_hash_overlay(pool, add->priorities, base->priorities);
  193     }
  194     else {
  195         n->priorities       = add->priorities? add->priorities : base->priorities;
  196     }
  197     n->push_diary_size      = H2_CONFIG_GET(add, base, push_diary_size);
  198     n->copy_files           = H2_CONFIG_GET(add, base, copy_files);
  199     n->output_buffered      = H2_CONFIG_GET(add, base, output_buffered);
  200     if (add->push_list && base->push_list) {
  201         n->push_list        = apr_array_append(pool, base->push_list, add->push_list);
  202     }
  203     else {
  204         n->push_list        = add->push_list? add->push_list : base->push_list;
  205     }
  206     n->early_hints          = H2_CONFIG_GET(add, base, early_hints);
  207     n->padding_bits         = H2_CONFIG_GET(add, base, padding_bits);
  208     n->padding_always       = H2_CONFIG_GET(add, base, padding_always);
  209     return n;
  210 }
  211 
  212 void *h2_config_merge_svr(apr_pool_t *pool, void *basev, void *addv)
  213 {
  214     return h2_config_merge(pool, basev, addv);
  215 }
  216 
  217 void *h2_config_create_dir(apr_pool_t *pool, char *x)
  218 {
  219     h2_dir_config *conf = (h2_dir_config *)apr_pcalloc(pool, sizeof(h2_dir_config));
  220     const char *s = x? x : "unknown";
  221     char *name = apr_pstrcat(pool, "dir[", s, "]", NULL);
  222     
  223     conf->name                 = name;
  224     conf->alt_svc_max_age      = DEF_VAL;
  225     conf->h2_upgrade           = DEF_VAL;
  226     conf->h2_push              = DEF_VAL;
  227     conf->early_hints          = DEF_VAL;
  228     return conf;
  229 }
  230 
  231 void *h2_config_merge_dir(apr_pool_t *pool, void *basev, void *addv)
  232 {
  233     h2_dir_config *base = (h2_dir_config *)basev;
  234     h2_dir_config *add = (h2_dir_config *)addv;
  235     h2_dir_config *n = (h2_dir_config *)apr_pcalloc(pool, sizeof(h2_dir_config));
  236 
  237     n->name = apr_pstrcat(pool, "merged[", add->name, ", ", base->name, "]", NULL);
  238     n->alt_svcs             = add->alt_svcs? add->alt_svcs : base->alt_svcs;
  239     n->alt_svc_max_age      = H2_CONFIG_GET(add, base, alt_svc_max_age);
  240     n->h2_upgrade           = H2_CONFIG_GET(add, base, h2_upgrade);
  241     n->h2_push              = H2_CONFIG_GET(add, base, h2_push);
  242     if (add->push_list && base->push_list) {
  243         n->push_list        = apr_array_append(pool, base->push_list, add->push_list);
  244     }
  245     else {
  246         n->push_list        = add->push_list? add->push_list : base->push_list;
  247     }
  248     n->early_hints          = H2_CONFIG_GET(add, base, early_hints);
  249     return n;
  250 }
  251 
  252 static apr_int64_t h2_srv_config_geti64(const h2_config *conf, h2_config_var_t var)
  253 {
  254     switch(var) {
  255         case H2_CONF_MAX_STREAMS:
  256             return H2_CONFIG_GET(conf, &defconf, h2_max_streams);
  257         case H2_CONF_WIN_SIZE:
  258             return H2_CONFIG_GET(conf, &defconf, h2_window_size);
  259         case H2_CONF_MIN_WORKERS:
  260             return H2_CONFIG_GET(conf, &defconf, min_workers);
  261         case H2_CONF_MAX_WORKERS:
  262             return H2_CONFIG_GET(conf, &defconf, max_workers);
  263         case H2_CONF_MAX_WORKER_IDLE_SECS:
  264             return H2_CONFIG_GET(conf, &defconf, max_worker_idle_secs);
  265         case H2_CONF_STREAM_MAX_MEM:
  266             return H2_CONFIG_GET(conf, &defconf, stream_max_mem_size);
  267         case H2_CONF_ALT_SVC_MAX_AGE:
  268             return H2_CONFIG_GET(conf, &defconf, alt_svc_max_age);
  269         case H2_CONF_SER_HEADERS:
  270             return H2_CONFIG_GET(conf, &defconf, serialize_headers);
  271         case H2_CONF_MODERN_TLS_ONLY:
  272             return H2_CONFIG_GET(conf, &defconf, modern_tls_only);
  273         case H2_CONF_UPGRADE:
  274             return H2_CONFIG_GET(conf, &defconf, h2_upgrade);
  275         case H2_CONF_DIRECT:
  276             return H2_CONFIG_GET(conf, &defconf, h2_direct);
  277         case H2_CONF_TLS_WARMUP_SIZE:
  278             return H2_CONFIG_GET(conf, &defconf, tls_warmup_size);
  279         case H2_CONF_TLS_COOLDOWN_SECS:
  280             return H2_CONFIG_GET(conf, &defconf, tls_cooldown_secs);
  281         case H2_CONF_PUSH:
  282             return H2_CONFIG_GET(conf, &defconf, h2_push);
  283         case H2_CONF_PUSH_DIARY_SIZE:
  284             return H2_CONFIG_GET(conf, &defconf, push_diary_size);
  285         case H2_CONF_COPY_FILES:
  286             return H2_CONFIG_GET(conf, &defconf, copy_files);
  287         case H2_CONF_EARLY_HINTS:
  288             return H2_CONFIG_GET(conf, &defconf, early_hints);
  289         case H2_CONF_PADDING_BITS:
  290             return H2_CONFIG_GET(conf, &defconf, padding_bits);
  291         case H2_CONF_PADDING_ALWAYS:
  292             return H2_CONFIG_GET(conf, &defconf, padding_always);
  293         case H2_CONF_OUTPUT_BUFFER:
  294             return H2_CONFIG_GET(conf, &defconf, output_buffered);
  295         default:
  296             return DEF_VAL;
  297     }
  298 }
  299 
  300 static void h2_srv_config_seti(h2_config *conf, h2_config_var_t var, int val)
  301 {
  302     switch(var) {
  303         case H2_CONF_MAX_STREAMS:
  304             H2_CONFIG_SET(conf, h2_max_streams, val);
  305             break;
  306         case H2_CONF_WIN_SIZE:
  307             H2_CONFIG_SET(conf, h2_window_size, val);
  308             break;
  309         case H2_CONF_MIN_WORKERS:
  310             H2_CONFIG_SET(conf, min_workers, val);
  311             break;
  312         case H2_CONF_MAX_WORKERS:
  313             H2_CONFIG_SET(conf, max_workers, val);
  314             break;
  315         case H2_CONF_MAX_WORKER_IDLE_SECS:
  316             H2_CONFIG_SET(conf, max_worker_idle_secs, val);
  317             break;
  318         case H2_CONF_STREAM_MAX_MEM:
  319             H2_CONFIG_SET(conf, stream_max_mem_size, val);
  320             break;
  321         case H2_CONF_ALT_SVC_MAX_AGE:
  322             H2_CONFIG_SET(conf, alt_svc_max_age, val);
  323             break;
  324         case H2_CONF_SER_HEADERS:
  325             H2_CONFIG_SET(conf, serialize_headers, val);
  326             break;
  327         case H2_CONF_MODERN_TLS_ONLY:
  328             H2_CONFIG_SET(conf, modern_tls_only, val);
  329             break;
  330         case H2_CONF_UPGRADE:
  331             H2_CONFIG_SET(conf, h2_upgrade, val);
  332             break;
  333         case H2_CONF_DIRECT:
  334             H2_CONFIG_SET(conf, h2_direct, val);
  335             break;
  336         case H2_CONF_TLS_WARMUP_SIZE:
  337             H2_CONFIG_SET(conf, tls_warmup_size, val);
  338             break;
  339         case H2_CONF_TLS_COOLDOWN_SECS:
  340             H2_CONFIG_SET(conf, tls_cooldown_secs, val);
  341             break;
  342         case H2_CONF_PUSH:
  343             H2_CONFIG_SET(conf, h2_push, val);
  344             break;
  345         case H2_CONF_PUSH_DIARY_SIZE:
  346             H2_CONFIG_SET(conf, push_diary_size, val);
  347             break;
  348         case H2_CONF_COPY_FILES:
  349             H2_CONFIG_SET(conf, copy_files, val);
  350             break;
  351         case H2_CONF_EARLY_HINTS:
  352             H2_CONFIG_SET(conf, early_hints, val);
  353             break;
  354         case H2_CONF_PADDING_BITS:
  355             H2_CONFIG_SET(conf, padding_bits, val);
  356             break;
  357         case H2_CONF_PADDING_ALWAYS:
  358             H2_CONFIG_SET(conf, padding_always, val);
  359             break;
  360         case H2_CONF_OUTPUT_BUFFER:
  361             H2_CONFIG_SET(conf, output_buffered, val);
  362             break;
  363         default:
  364             break;
  365     }
  366 }
  367 
  368 static void h2_srv_config_seti64(h2_config *conf, h2_config_var_t var, apr_int64_t val)
  369 {
  370     switch(var) {
  371         case H2_CONF_TLS_WARMUP_SIZE:
  372             H2_CONFIG_SET(conf, tls_warmup_size, val);
  373             break;
  374         default:
  375             h2_srv_config_seti(conf, var, (int)val);
  376             break;
  377     }
  378 }
  379 
  380 static h2_config *h2_config_sget(server_rec *s)
  381 {
  382     h2_config *cfg = (h2_config *)ap_get_module_config(s->module_config, 
  383                                                        &http2_module);
  384     ap_assert(cfg);
  385     return cfg;
  386 }
  387 
  388 static const h2_dir_config *h2_config_rget(request_rec *r)
  389 {
  390     h2_dir_config *cfg = (h2_dir_config *)ap_get_module_config(r->per_dir_config, 
  391                                                                &http2_module);
  392     ap_assert(cfg);
  393     return cfg;
  394 }
  395 
  396 static apr_int64_t h2_dir_config_geti64(const h2_dir_config *conf, h2_config_var_t var)
  397 {
  398     switch(var) {
  399         case H2_CONF_ALT_SVC_MAX_AGE:
  400             return H2_CONFIG_GET(conf, &defdconf, alt_svc_max_age);
  401         case H2_CONF_UPGRADE:
  402             return H2_CONFIG_GET(conf, &defdconf, h2_upgrade);
  403         case H2_CONF_PUSH:
  404             return H2_CONFIG_GET(conf, &defdconf, h2_push);
  405         case H2_CONF_EARLY_HINTS:
  406             return H2_CONFIG_GET(conf, &defdconf, early_hints);
  407 
  408         default:
  409             return DEF_VAL;
  410     }
  411 }
  412 
  413 static void h2_config_seti(h2_dir_config *dconf, h2_config *conf, h2_config_var_t var, int val)
  414 {
  415     int set_srv = !dconf;
  416     if (dconf) {
  417         switch(var) {
  418             case H2_CONF_ALT_SVC_MAX_AGE:
  419                 H2_CONFIG_SET(dconf, alt_svc_max_age, val);
  420                 break;
  421             case H2_CONF_UPGRADE:
  422                 H2_CONFIG_SET(dconf, h2_upgrade, val);
  423                 break;
  424             case H2_CONF_PUSH:
  425                 H2_CONFIG_SET(dconf, h2_push, val);
  426                 break;
  427             case H2_CONF_EARLY_HINTS:
  428                 H2_CONFIG_SET(dconf, early_hints, val);
  429                 break;
  430             default:
  431                 /* not handled in dir_conf */
  432                 set_srv = 1;
  433                 break;
  434         }
  435     }
  436 
  437     if (set_srv) {
  438         h2_srv_config_seti(conf, var, val);
  439     }
  440 }
  441 
  442 static void h2_config_seti64(h2_dir_config *dconf, h2_config *conf, h2_config_var_t var, apr_int64_t val)
  443 {
  444     int set_srv = !dconf;
  445     if (dconf) {
  446         switch(var) {
  447             default:
  448                 /* not handled in dir_conf */
  449                 set_srv = 1;
  450                 break;
  451         }
  452     }
  453 
  454     if (set_srv) {
  455         h2_srv_config_seti64(conf, var, val);
  456     }
  457 }
  458 
  459 static const h2_config *h2_config_get(conn_rec *c)
  460 {
  461     h2_ctx *ctx = h2_ctx_get(c, 0);
  462     
  463     if (ctx) {
  464         if (ctx->config) {
  465             return ctx->config;
  466         }
  467         else if (ctx->server) {
  468             ctx->config = h2_config_sget(ctx->server);
  469             return ctx->config;
  470         }
  471     }
  472     
  473     return h2_config_sget(c->base_server);
  474 }
  475 
  476 int h2_config_cgeti(conn_rec *c, h2_config_var_t var)
  477 {
  478     return (int)h2_srv_config_geti64(h2_config_get(c), var);
  479 }
  480 
  481 apr_int64_t h2_config_cgeti64(conn_rec *c, h2_config_var_t var)
  482 {
  483     return h2_srv_config_geti64(h2_config_get(c), var);
  484 }
  485 
  486 int h2_config_sgeti(server_rec *s, h2_config_var_t var)
  487 {
  488     return (int)h2_srv_config_geti64(h2_config_sget(s), var);
  489 }
  490 
  491 apr_int64_t h2_config_sgeti64(server_rec *s, h2_config_var_t var)
  492 {
  493     return h2_srv_config_geti64(h2_config_sget(s), var);
  494 }
  495 
  496 int h2_config_geti(request_rec *r, server_rec *s, h2_config_var_t var)
  497 {
  498     return (int)h2_config_geti64(r, s, var);
  499 }
  500 
  501 apr_int64_t h2_config_geti64(request_rec *r, server_rec *s, h2_config_var_t var)
  502 {
  503     apr_int64_t mode = r? (int)h2_dir_config_geti64(h2_config_rget(r), var) : DEF_VAL;
  504     return (mode != DEF_VAL)? mode : h2_config_sgeti64(s, var);
  505 }
  506 
  507 int h2_config_rgeti(request_rec *r, h2_config_var_t var)
  508 {
  509     return h2_config_geti(r, r->server, var);
  510 }
  511 
  512 apr_int64_t h2_config_rgeti64(request_rec *r, h2_config_var_t var)
  513 {
  514     return h2_config_geti64(r, r->server, var);
  515 }
  516 
  517 apr_array_header_t *h2_config_push_list(request_rec *r)
  518 {
  519     const h2_config *sconf;
  520     const h2_dir_config *conf = h2_config_rget(r);
  521     
  522     if (conf && conf->push_list) {
  523         return conf->push_list;
  524     }
  525     sconf = h2_config_sget(r->server); 
  526     return sconf? sconf->push_list : NULL;
  527 }
  528 
  529 apr_array_header_t *h2_config_alt_svcs(request_rec *r)
  530 {
  531     const h2_config *sconf;
  532     const h2_dir_config *conf = h2_config_rget(r);
  533     
  534     if (conf && conf->alt_svcs) {
  535         return conf->alt_svcs;
  536     }
  537     sconf = h2_config_sget(r->server); 
  538     return sconf? sconf->alt_svcs : NULL;
  539 }
  540 
  541 const struct h2_priority *h2_cconfig_get_priority(conn_rec *c, const char *content_type)
  542 {
  543     const h2_config *conf = h2_config_get(c);
  544     if (content_type && conf->priorities) {
  545         apr_ssize_t len = (apr_ssize_t)strcspn(content_type, "; \t");
  546         h2_priority *prio = apr_hash_get(conf->priorities, content_type, len);
  547         return prio? prio : apr_hash_get(conf->priorities, "*", 1);
  548     }
  549     return NULL;
  550 }
  551 
  552 static const char *h2_conf_set_max_streams(cmd_parms *cmd,
  553                                            void *dirconf, const char *value)
  554 {
  555     apr_int64_t ival = (int)apr_atoi64(value);
  556     if (ival < 1) {
  557         return "value must be > 0";
  558     }
  559     CONFIG_CMD_SET64(cmd, dirconf, H2_CONF_MAX_STREAMS, ival);
  560     return NULL;
  561 }
  562 
  563 static const char *h2_conf_set_window_size(cmd_parms *cmd,
  564                                            void *dirconf, const char *value)
  565 {
  566     int val = (int)apr_atoi64(value);
  567     if (val < 1024) {
  568         return "value must be >= 1024";
  569     }
  570     CONFIG_CMD_SET(cmd, dirconf, H2_CONF_WIN_SIZE, val);
  571     return NULL;
  572 }
  573 
  574 static const char *h2_conf_set_min_workers(cmd_parms *cmd,
  575                                            void *dirconf, const char *value)
  576 {
  577     int val = (int)apr_atoi64(value);
  578     if (val < 1) {
  579         return "value must be > 0";
  580     }
  581     CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MIN_WORKERS, val);
  582     return NULL;
  583 }
  584 
  585 static const char *h2_conf_set_max_workers(cmd_parms *cmd,
  586                                            void *dirconf, const char *value)
  587 {
  588     int val = (int)apr_atoi64(value);
  589     if (val < 1) {
  590         return "value must be > 0";
  591     }
  592     CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MAX_WORKERS, val);
  593     return NULL;
  594 }
  595 
  596 static const char *h2_conf_set_max_worker_idle_secs(cmd_parms *cmd,
  597                                                     void *dirconf, const char *value)
  598 {
  599     int val = (int)apr_atoi64(value);
  600     if (val < 1) {
  601         return "value must be > 0";
  602     }
  603     CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MAX_WORKER_IDLE_SECS, val);
  604     return NULL;
  605 }
  606 
  607 static const char *h2_conf_set_stream_max_mem_size(cmd_parms *cmd,
  608                                                    void *dirconf, const char *value)
  609 {
  610     int val = (int)apr_atoi64(value);
  611     if (val < 1024) {
  612         return "value must be >= 1024";
  613     }
  614     CONFIG_CMD_SET(cmd, dirconf, H2_CONF_STREAM_MAX_MEM, val);
  615     return NULL;
  616 }
  617 
  618 static const char *h2_add_alt_svc(cmd_parms *cmd,
  619                                   void *dirconf, const char *value)
  620 {
  621     if (value && *value) {
  622         h2_alt_svc *as = h2_alt_svc_parse(value, cmd->pool);
  623         if (!as) {
  624             return "unable to parse alt-svc specifier";
  625         }
  626 
  627         if (cmd->path) {
  628             h2_dir_config *dcfg = (h2_dir_config *)dirconf;
  629             if (!dcfg->alt_svcs) {
  630                 dcfg->alt_svcs = apr_array_make(cmd->pool, 5, sizeof(h2_alt_svc*));
  631             }
  632             APR_ARRAY_PUSH(dcfg->alt_svcs, h2_alt_svc*) = as;
  633         }
  634         else {
  635             h2_config *cfg = (h2_config *)h2_config_sget(cmd->server);
  636             if (!cfg->alt_svcs) {
  637                 cfg->alt_svcs = apr_array_make(cmd->pool, 5, sizeof(h2_alt_svc*));
  638             }
  639             APR_ARRAY_PUSH(cfg->alt_svcs, h2_alt_svc*) = as;
  640         }
  641     }
  642     return NULL;
  643 }
  644 
  645 static const char *h2_conf_set_alt_svc_max_age(cmd_parms *cmd,
  646                                                void *dirconf, const char *value)
  647 {
  648     int val = (int)apr_atoi64(value);
  649     CONFIG_CMD_SET(cmd, dirconf, H2_CONF_ALT_SVC_MAX_AGE, val);
  650     return NULL;
  651 }
  652 
  653 static const char *h2_conf_set_session_extra_files(cmd_parms *cmd,
  654                                                    void *dirconf, const char *value)
  655 {
  656     /* deprecated, ignore */
  657     (void)dirconf;
  658     (void)value;
  659     ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, cmd->pool, /* NO LOGNO */
  660                   "H2SessionExtraFiles is obsolete and will be ignored");
  661     return NULL;
  662 }
  663 
  664 static const char *h2_conf_set_serialize_headers(cmd_parms *cmd,
  665                                                  void *dirconf, const char *value)
  666 {
  667     if (!strcasecmp(value, "On")) {
  668         CONFIG_CMD_SET(cmd, dirconf, H2_CONF_SER_HEADERS, 1);
  669         return NULL;
  670     }
  671     else if (!strcasecmp(value, "Off")) {
  672         CONFIG_CMD_SET(cmd, dirconf, H2_CONF_SER_HEADERS, 0);
  673         return NULL;
  674     }
  675     return "value must be On or Off";
  676 }
  677 
  678 static const char *h2_conf_set_direct(cmd_parms *cmd,
  679                                       void *dirconf, const char *value)
  680 {
  681     if (!strcasecmp(value, "On")) {
  682         CONFIG_CMD_SET(cmd, dirconf, H2_CONF_DIRECT, 1);
  683         return NULL;
  684     }
  685     else if (!strcasecmp(value, "Off")) {
  686         CONFIG_CMD_SET(cmd, dirconf, H2_CONF_DIRECT, 0);
  687         return NULL;
  688     }
  689     return "value must be On or Off";
  690 }
  691 
  692 static const char *h2_conf_set_push(cmd_parms *cmd, void *dirconf, const char *value)
  693 {
  694     if (!strcasecmp(value, "On")) {
  695         CONFIG_CMD_SET(cmd, dirconf, H2_CONF_PUSH, 1);
  696         return NULL;
  697     }
  698     else if (!strcasecmp(value, "Off")) {
  699         CONFIG_CMD_SET(cmd, dirconf, H2_CONF_PUSH, 0);
  700         return NULL;
  701     }
  702     return "value must be On or Off";
  703 }
  704 
  705 static const char *h2_conf_add_push_priority(cmd_parms *cmd, void *_cfg,
  706                                              const char *ctype, const char *sdependency,
  707                                              const char *sweight)
  708 {
  709     h2_config *cfg = (h2_config *)h2_config_sget(cmd->server);
  710     const char *sdefweight = "16";         /* default AFTER weight */
  711     h2_dependency dependency;
  712     h2_priority *priority;
  713     int weight;
  714  
  715     (void)_cfg;
  716     if (!*ctype) {
  717         return "1st argument must be a mime-type, like 'text/css' or '*'";
  718     }
  719     
  720     if (!sweight) {
  721         /* 2 args only, but which one? */
  722         if (apr_isdigit(sdependency[0])) {
  723             sweight = sdependency;
  724             sdependency = "AFTER";        /* default dependency */
  725         }
  726     }
  727     
  728     if (!strcasecmp("AFTER", sdependency)) {
  729         dependency = H2_DEPENDANT_AFTER;
  730     } 
  731     else if (!strcasecmp("BEFORE", sdependency)) {
  732         dependency = H2_DEPENDANT_BEFORE;
  733         if (sweight) {
  734             return "dependency 'Before' does not allow a weight";
  735         }
  736     } 
  737     else if (!strcasecmp("INTERLEAVED", sdependency)) {
  738         dependency = H2_DEPENDANT_INTERLEAVED;
  739         sdefweight = "256";        /* default INTERLEAVED weight */
  740     }
  741     else {
  742         return "dependency must be one of 'After', 'Before' or 'Interleaved'";
  743     }
  744     
  745     weight = (int)apr_atoi64(sweight? sweight : sdefweight);
  746     if (weight < NGHTTP2_MIN_WEIGHT) {
  747         return apr_psprintf(cmd->pool, "weight must be a number >= %d",
  748                             NGHTTP2_MIN_WEIGHT);
  749     }
  750     
  751     priority = apr_pcalloc(cmd->pool, sizeof(*priority));
  752     priority->dependency = dependency;
  753     priority->weight = weight;
  754     
  755     if (!cfg->priorities) {
  756         cfg->priorities = apr_hash_make(cmd->pool);
  757     }
  758     apr_hash_set(cfg->priorities, ctype, (apr_ssize_t)strlen(ctype), priority);
  759     return NULL;
  760 }
  761 
  762 static const char *h2_conf_set_modern_tls_only(cmd_parms *cmd,
  763                                                void *dirconf, const char *value)
  764 {
  765     if (!strcasecmp(value, "On")) {
  766         CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MODERN_TLS_ONLY, 1);
  767         return NULL;
  768     }
  769     else if (!strcasecmp(value, "Off")) {
  770         CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MODERN_TLS_ONLY, 0);
  771         return NULL;
  772     }
  773     return "value must be On or Off";
  774 }
  775 
  776 static const char *h2_conf_set_upgrade(cmd_parms *cmd,
  777                                        void *dirconf, const char *value)
  778 {
  779     if (!strcasecmp(value, "On")) {
  780         CONFIG_CMD_SET(cmd, dirconf, H2_CONF_UPGRADE, 1);
  781         return NULL;
  782     }
  783     else if (!strcasecmp(value, "Off")) {
  784         CONFIG_CMD_SET(cmd, dirconf, H2_CONF_UPGRADE, 0);
  785         return NULL;
  786     }
  787     return "value must be On or Off";
  788 }
  789 
  790 static const char *h2_conf_set_tls_warmup_size(cmd_parms *cmd,
  791                                                void *dirconf, const char *value)
  792 {
  793     apr_int64_t val = apr_atoi64(value);
  794     CONFIG_CMD_SET64(cmd, dirconf, H2_CONF_TLS_WARMUP_SIZE, val);
  795     return NULL;
  796 }
  797 
  798 static const char *h2_conf_set_tls_cooldown_secs(cmd_parms *cmd,
  799                                                  void *dirconf, const char *value)
  800 {
  801     apr_int64_t val = (int)apr_atoi64(value);
  802     CONFIG_CMD_SET64(cmd, dirconf, H2_CONF_TLS_COOLDOWN_SECS, val);
  803     return NULL;
  804 }
  805 
  806 static const char *h2_conf_set_push_diary_size(cmd_parms *cmd,
  807                                                void *dirconf, const char *value)
  808 {
  809     int val = (int)apr_atoi64(value);
  810     if (val < 0) {
  811         return "value must be >= 0";
  812     }
  813     if (val > 0 && (val & (val-1))) {
  814         return "value must a power of 2";
  815     }
  816     if (val > (1 << 15)) {
  817         return "value must <= 65536";
  818     }
  819     CONFIG_CMD_SET(cmd, dirconf, H2_CONF_PUSH_DIARY_SIZE, val);
  820     return NULL;
  821 }
  822 
  823 static const char *h2_conf_set_copy_files(cmd_parms *cmd,
  824                                           void *dirconf, const char *value)
  825 {
  826     if (!strcasecmp(value, "On")) {
  827         CONFIG_CMD_SET(cmd, dirconf, H2_CONF_COPY_FILES, 1);
  828         return NULL;
  829     }
  830     else if (!strcasecmp(value, "Off")) {
  831         CONFIG_CMD_SET(cmd, dirconf, H2_CONF_COPY_FILES, 0);
  832         return NULL;
  833     }
  834     return "value must be On or Off";
  835 }
  836 
  837 static void add_push(apr_array_header_t **plist, apr_pool_t *pool, h2_push_res *push)
  838 {
  839     h2_push_res *new;
  840     if (!*plist) {
  841         *plist = apr_array_make(pool, 10, sizeof(*push));
  842     }
  843     new = apr_array_push(*plist);
  844     new->uri_ref = push->uri_ref;
  845     new->critical = push->critical;
  846 }
  847 
  848 static const char *h2_conf_add_push_res(cmd_parms *cmd, void *dirconf,
  849                                         const char *arg1, const char *arg2,
  850                                         const char *arg3)
  851 {
  852     h2_push_res push;
  853     const char *last = arg3;
  854     
  855     memset(&push, 0, sizeof(push));
  856     if (!strcasecmp("add", arg1)) {
  857         push.uri_ref = arg2;
  858     }
  859     else {
  860         push.uri_ref = arg1;
  861         last = arg2;
  862         if (arg3) {
  863             return "too many parameter";
  864         }
  865     }
  866     
  867     if (last) {
  868         if (!strcasecmp("critical", last)) {
  869             push.critical = 1;
  870         }
  871         else {
  872             return "unknown last parameter";
  873         }
  874     }
  875 
  876     if (cmd->path) {
  877         add_push(&(((h2_dir_config*)dirconf)->push_list), cmd->pool, &push);
  878     }
  879     else {
  880         add_push(&(h2_config_sget(cmd->server)->push_list), cmd->pool, &push);
  881     }
  882     return NULL;
  883 }
  884 
  885 static const char *h2_conf_set_early_hints(cmd_parms *cmd,
  886                                            void *dirconf, const char *value)
  887 {
  888     int val;
  889 
  890     if (!strcasecmp(value, "On")) val = 1;
  891     else if (!strcasecmp(value, "Off")) val = 0;
  892     else return "value must be On or Off";
  893     
  894     CONFIG_CMD_SET(cmd, dirconf, H2_CONF_EARLY_HINTS, val);
  895     if (cmd->path) {
  896         ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, cmd->pool, 
  897                             "H2EarlyHints = %d on path %s", val, cmd->path);
  898     }
  899     return NULL;
  900 }
  901 
  902 static const char *h2_conf_set_padding(cmd_parms *cmd, void *dirconf, const char *value)
  903 {
  904     int val;
  905     
  906     val = (int)apr_atoi64(value);
  907     if (val < 0) {
  908         return "number of bits must be >= 0";
  909     }
  910     if (val > 8) {
  911         return "number of bits must be <= 8";
  912     }
  913     CONFIG_CMD_SET(cmd, dirconf, H2_CONF_PADDING_BITS, val);
  914     return NULL;
  915 }
  916 
  917 static const char *h2_conf_set_output_buffer(cmd_parms *cmd,
  918                                       void *dirconf, const char *value)
  919 {
  920     if (!strcasecmp(value, "On")) {
  921         CONFIG_CMD_SET(cmd, dirconf, H2_CONF_OUTPUT_BUFFER, 1);
  922         return NULL;
  923     }
  924     else if (!strcasecmp(value, "Off")) {
  925         CONFIG_CMD_SET(cmd, dirconf, H2_CONF_OUTPUT_BUFFER, 0);
  926         return NULL;
  927     }
  928     return "value must be On or Off";
  929 }
  930 
  931 void h2_get_num_workers(server_rec *s, int *minw, int *maxw)
  932 {
  933     int threads_per_child = 0;
  934 
  935     *minw = h2_config_sgeti(s, H2_CONF_MIN_WORKERS);
  936     *maxw = h2_config_sgeti(s, H2_CONF_MAX_WORKERS);    
  937     ap_mpm_query(AP_MPMQ_MAX_THREADS, &threads_per_child);
  938 
  939     if (*minw <= 0) {
  940         *minw = threads_per_child;
  941     }
  942     if (*maxw <= 0) {
  943         /* As a default, this seems to work quite well under mpm_event. 
  944          * For people enabling http2 under mpm_prefork, start 4 threads unless 
  945          * configured otherwise. People get unhappy if their http2 requests are 
  946          * blocking each other. */
  947         *maxw = 3 * (*minw) / 2;
  948         if (*maxw < 4) {
  949             *maxw = 4;
  950         }
  951     }
  952 }
  953 
  954 #define AP_END_CMD     AP_INIT_TAKE1(NULL, NULL, NULL, RSRC_CONF, NULL)
  955 
  956 const command_rec h2_cmds[] = {
  957     AP_INIT_TAKE1("H2MaxSessionStreams", h2_conf_set_max_streams, NULL,
  958                   RSRC_CONF, "maximum number of open streams per session"),
  959     AP_INIT_TAKE1("H2WindowSize", h2_conf_set_window_size, NULL,
  960                   RSRC_CONF, "window size on client DATA"),
  961     AP_INIT_TAKE1("H2MinWorkers", h2_conf_set_min_workers, NULL,
  962                   RSRC_CONF, "minimum number of worker threads per child"),
  963     AP_INIT_TAKE1("H2MaxWorkers", h2_conf_set_max_workers, NULL,
  964                   RSRC_CONF, "maximum number of worker threads per child"),
  965     AP_INIT_TAKE1("H2MaxWorkerIdleSeconds", h2_conf_set_max_worker_idle_secs, NULL,
  966                   RSRC_CONF, "maximum number of idle seconds before a worker shuts down"),
  967     AP_INIT_TAKE1("H2StreamMaxMemSize", h2_conf_set_stream_max_mem_size, NULL,
  968                   RSRC_CONF, "maximum number of bytes buffered in memory for a stream"),
  969     AP_INIT_TAKE1("H2AltSvc", h2_add_alt_svc, NULL,
  970                   RSRC_CONF, "adds an Alt-Svc for this server"),
  971     AP_INIT_TAKE1("H2AltSvcMaxAge", h2_conf_set_alt_svc_max_age, NULL,
  972                   RSRC_CONF, "set the maximum age (in seconds) that client can rely on alt-svc information"),
  973     AP_INIT_TAKE1("H2SerializeHeaders", h2_conf_set_serialize_headers, NULL,
  974                   RSRC_CONF, "on to enable header serialization for compatibility"),
  975     AP_INIT_TAKE1("H2ModernTLSOnly", h2_conf_set_modern_tls_only, NULL,
  976                   RSRC_CONF, "off to not impose RFC 7540 restrictions on TLS"),
  977     AP_INIT_TAKE1("H2Upgrade", h2_conf_set_upgrade, NULL,
  978                   RSRC_CONF|OR_AUTHCFG, "on to allow HTTP/1 Upgrades to h2/h2c"),
  979     AP_INIT_TAKE1("H2Direct", h2_conf_set_direct, NULL,
  980                   RSRC_CONF, "on to enable direct HTTP/2 mode"),
  981     AP_INIT_TAKE1("H2SessionExtraFiles", h2_conf_set_session_extra_files, NULL,
  982                   RSRC_CONF, "number of extra file a session might keep open (obsolete)"),
  983     AP_INIT_TAKE1("H2TLSWarmUpSize", h2_conf_set_tls_warmup_size, NULL,
  984                   RSRC_CONF, "number of bytes on TLS connection before doing max writes"),
  985     AP_INIT_TAKE1("H2TLSCoolDownSecs", h2_conf_set_tls_cooldown_secs, NULL,
  986                   RSRC_CONF, "seconds of idle time on TLS before shrinking writes"),
  987     AP_INIT_TAKE1("H2Push", h2_conf_set_push, NULL,
  988                   RSRC_CONF|OR_AUTHCFG, "off to disable HTTP/2 server push"),
  989     AP_INIT_TAKE23("H2PushPriority", h2_conf_add_push_priority, NULL,
  990                   RSRC_CONF, "define priority of PUSHed resources per content type"),
  991     AP_INIT_TAKE1("H2PushDiarySize", h2_conf_set_push_diary_size, NULL,
  992                   RSRC_CONF, "size of push diary"),
  993     AP_INIT_TAKE1("H2CopyFiles", h2_conf_set_copy_files, NULL,
  994                   OR_FILEINFO, "on to perform copy of file data"),
  995     AP_INIT_TAKE123("H2PushResource", h2_conf_add_push_res, NULL,
  996                    OR_FILEINFO|OR_AUTHCFG, "add a resource to be pushed in this location/on this server."),
  997     AP_INIT_TAKE1("H2EarlyHints", h2_conf_set_early_hints, NULL,
  998                   RSRC_CONF, "on to enable interim status 103 responses"),
  999     AP_INIT_TAKE1("H2Padding", h2_conf_set_padding, NULL,
 1000                   RSRC_CONF, "set payload padding"),
 1001     AP_INIT_TAKE1("H2OutputBuffering", h2_conf_set_output_buffer, NULL,
 1002                   RSRC_CONF, "set stream output buffer on/off"),
 1003     AP_END_CMD
 1004 };
 1005 
 1006