Blame modules/http2/h2_config.c

Packit 90a5c9
/* Licensed to the Apache Software Foundation (ASF) under one or more
Packit 90a5c9
 * contributor license agreements.  See the NOTICE file distributed with
Packit 90a5c9
 * this work for additional information regarding copyright ownership.
Packit 90a5c9
 * The ASF licenses this file to You under the Apache License, Version 2.0
Packit 90a5c9
 * (the "License"); you may not use this file except in compliance with
Packit 90a5c9
 * the License.  You may obtain a copy of the License at
Packit 90a5c9
 *
Packit 90a5c9
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 90a5c9
 *
Packit 90a5c9
 * Unless required by applicable law or agreed to in writing, software
Packit 90a5c9
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 90a5c9
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 90a5c9
 * See the License for the specific language governing permissions and
Packit 90a5c9
 * limitations under the License.
Packit 90a5c9
 */
Packit 90a5c9
 
Packit 90a5c9
#include <assert.h>
Packit 90a5c9
Packit 90a5c9
#include <apr_hash.h>
Packit 90a5c9
#include <apr_lib.h>
Packit 90a5c9
Packit 90a5c9
#include <httpd.h>
Packit 90a5c9
#include <http_core.h>
Packit 90a5c9
#include <http_config.h>
Packit 90a5c9
#include <http_log.h>
Packit 90a5c9
#include <http_vhost.h>
Packit 90a5c9
Packit 90a5c9
#include <ap_mpm.h>
Packit 90a5c9
Packit 90a5c9
#include <apr_strings.h>
Packit 90a5c9
Packit 90a5c9
#include "h2.h"
Packit 90a5c9
#include "h2_alt_svc.h"
Packit 90a5c9
#include "h2_ctx.h"
Packit 90a5c9
#include "h2_conn.h"
Packit 90a5c9
#include "h2_config.h"
Packit 90a5c9
#include "h2_h2.h"
Packit 90a5c9
#include "h2_private.h"
Packit 90a5c9
Packit 90a5c9
#define DEF_VAL     (-1)
Packit 90a5c9
Packit 90a5c9
#define H2_CONFIG_GET(a, b, n) \
Packit 90a5c9
    (((a)->n == DEF_VAL)? (b) : (a))->n
Packit 90a5c9
Packit 90a5c9
static h2_config defconf = {
Packit 90a5c9
    "default",
Packit 90a5c9
    100,                    /* max_streams */
Packit 90a5c9
    H2_INITIAL_WINDOW_SIZE, /* window_size */
Packit 90a5c9
    -1,                     /* min workers */
Packit 90a5c9
    -1,                     /* max workers */
Packit 90a5c9
    10 * 60,                /* max workers idle secs */
Packit 90a5c9
    32 * 1024,              /* stream max mem size */
Packit 90a5c9
    NULL,                   /* no alt-svcs */
Packit 90a5c9
    -1,                     /* alt-svc max age */
Packit 90a5c9
    0,                      /* serialize headers */
Packit 90a5c9
    -1,                     /* h2 direct mode */
Packit 90a5c9
    1,                      /* modern TLS only */
Packit 90a5c9
    -1,                     /* HTTP/1 Upgrade support */
Packit 90a5c9
    1024*1024,              /* TLS warmup size */
Packit 90a5c9
    1,                      /* TLS cooldown secs */
Packit 90a5c9
    1,                      /* HTTP/2 server push enabled */
Packit 90a5c9
    NULL,                   /* map of content-type to priorities */
Packit 90a5c9
    256,                    /* push diary size */
Packit 90a5c9
    0,                      /* copy files across threads */
Packit 90a5c9
    NULL,                   /* push list */
Packit 90a5c9
    0,                      /* early hints, http status 103 */
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
void h2_config_init(apr_pool_t *pool)
Packit 90a5c9
{
Packit 90a5c9
    (void)pool;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static void *h2_config_create(apr_pool_t *pool,
Packit 90a5c9
                              const char *prefix, const char *x)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *conf = (h2_config *)apr_pcalloc(pool, sizeof(h2_config));
Packit 90a5c9
    const char *s = x? x : "unknown";
Packit 90a5c9
    char *name = apr_pstrcat(pool, prefix, "[", s, "]", NULL);
Packit 90a5c9
    
Packit 90a5c9
    conf->name                 = name;
Packit 90a5c9
    conf->h2_max_streams       = DEF_VAL;
Packit 90a5c9
    conf->h2_window_size       = DEF_VAL;
Packit 90a5c9
    conf->min_workers          = DEF_VAL;
Packit 90a5c9
    conf->max_workers          = DEF_VAL;
Packit 90a5c9
    conf->max_worker_idle_secs = DEF_VAL;
Packit 90a5c9
    conf->stream_max_mem_size  = DEF_VAL;
Packit 90a5c9
    conf->alt_svc_max_age      = DEF_VAL;
Packit 90a5c9
    conf->serialize_headers    = DEF_VAL;
Packit 90a5c9
    conf->h2_direct            = DEF_VAL;
Packit 90a5c9
    conf->modern_tls_only      = DEF_VAL;
Packit 90a5c9
    conf->h2_upgrade           = DEF_VAL;
Packit 90a5c9
    conf->tls_warmup_size      = DEF_VAL;
Packit 90a5c9
    conf->tls_cooldown_secs    = DEF_VAL;
Packit 90a5c9
    conf->h2_push              = DEF_VAL;
Packit 90a5c9
    conf->priorities           = NULL;
Packit 90a5c9
    conf->push_diary_size      = DEF_VAL;
Packit 90a5c9
    conf->copy_files           = DEF_VAL;
Packit 90a5c9
    conf->push_list            = NULL;
Packit 90a5c9
    conf->early_hints          = DEF_VAL;
Packit 90a5c9
    return conf;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void *h2_config_create_svr(apr_pool_t *pool, server_rec *s)
Packit 90a5c9
{
Packit 90a5c9
    return h2_config_create(pool, "srv", s->defn_name);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void *h2_config_create_dir(apr_pool_t *pool, char *x)
Packit 90a5c9
{
Packit 90a5c9
    return h2_config_create(pool, "dir", x);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *base = (h2_config *)basev;
Packit 90a5c9
    h2_config *add = (h2_config *)addv;
Packit 90a5c9
    h2_config *n = (h2_config *)apr_pcalloc(pool, sizeof(h2_config));
Packit 90a5c9
    char *name = apr_pstrcat(pool, "merged[", add->name, ", ", base->name, "]", NULL);
Packit 90a5c9
    n->name = name;
Packit 90a5c9
Packit 90a5c9
    n->h2_max_streams       = H2_CONFIG_GET(add, base, h2_max_streams);
Packit 90a5c9
    n->h2_window_size       = H2_CONFIG_GET(add, base, h2_window_size);
Packit 90a5c9
    n->min_workers          = H2_CONFIG_GET(add, base, min_workers);
Packit 90a5c9
    n->max_workers          = H2_CONFIG_GET(add, base, max_workers);
Packit 90a5c9
    n->max_worker_idle_secs = H2_CONFIG_GET(add, base, max_worker_idle_secs);
Packit 90a5c9
    n->stream_max_mem_size  = H2_CONFIG_GET(add, base, stream_max_mem_size);
Packit 90a5c9
    n->alt_svcs             = add->alt_svcs? add->alt_svcs : base->alt_svcs;
Packit 90a5c9
    n->alt_svc_max_age      = H2_CONFIG_GET(add, base, alt_svc_max_age);
Packit 90a5c9
    n->serialize_headers    = H2_CONFIG_GET(add, base, serialize_headers);
Packit 90a5c9
    n->h2_direct            = H2_CONFIG_GET(add, base, h2_direct);
Packit 90a5c9
    n->modern_tls_only      = H2_CONFIG_GET(add, base, modern_tls_only);
Packit 90a5c9
    n->h2_upgrade           = H2_CONFIG_GET(add, base, h2_upgrade);
Packit 90a5c9
    n->tls_warmup_size      = H2_CONFIG_GET(add, base, tls_warmup_size);
Packit 90a5c9
    n->tls_cooldown_secs    = H2_CONFIG_GET(add, base, tls_cooldown_secs);
Packit 90a5c9
    n->h2_push              = H2_CONFIG_GET(add, base, h2_push);
Packit 90a5c9
    if (add->priorities && base->priorities) {
Packit 90a5c9
        n->priorities       = apr_hash_overlay(pool, add->priorities, base->priorities);
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        n->priorities       = add->priorities? add->priorities : base->priorities;
Packit 90a5c9
    }
Packit 90a5c9
    n->push_diary_size      = H2_CONFIG_GET(add, base, push_diary_size);
Packit 90a5c9
    n->copy_files           = H2_CONFIG_GET(add, base, copy_files);
Packit 90a5c9
    if (add->push_list && base->push_list) {
Packit 90a5c9
        n->push_list        = apr_array_append(pool, base->push_list, add->push_list);
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        n->push_list        = add->push_list? add->push_list : base->push_list;
Packit 90a5c9
    }
Packit 90a5c9
    n->early_hints          = H2_CONFIG_GET(add, base, early_hints);
Packit 90a5c9
    return n;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void *h2_config_merge_dir(apr_pool_t *pool, void *basev, void *addv)
Packit 90a5c9
{
Packit 90a5c9
    return h2_config_merge(pool, basev, addv);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void *h2_config_merge_svr(apr_pool_t *pool, void *basev, void *addv)
Packit 90a5c9
{
Packit 90a5c9
    return h2_config_merge(pool, basev, addv);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
int h2_config_geti(const h2_config *conf, h2_config_var_t var)
Packit 90a5c9
{
Packit 90a5c9
    return (int)h2_config_geti64(conf, var);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
apr_int64_t h2_config_geti64(const h2_config *conf, h2_config_var_t var)
Packit 90a5c9
{
Packit 90a5c9
    switch(var) {
Packit 90a5c9
        case H2_CONF_MAX_STREAMS:
Packit 90a5c9
            return H2_CONFIG_GET(conf, &defconf, h2_max_streams);
Packit 90a5c9
        case H2_CONF_WIN_SIZE:
Packit 90a5c9
            return H2_CONFIG_GET(conf, &defconf, h2_window_size);
Packit 90a5c9
        case H2_CONF_MIN_WORKERS:
Packit 90a5c9
            return H2_CONFIG_GET(conf, &defconf, min_workers);
Packit 90a5c9
        case H2_CONF_MAX_WORKERS:
Packit 90a5c9
            return H2_CONFIG_GET(conf, &defconf, max_workers);
Packit 90a5c9
        case H2_CONF_MAX_WORKER_IDLE_SECS:
Packit 90a5c9
            return H2_CONFIG_GET(conf, &defconf, max_worker_idle_secs);
Packit 90a5c9
        case H2_CONF_STREAM_MAX_MEM:
Packit 90a5c9
            return H2_CONFIG_GET(conf, &defconf, stream_max_mem_size);
Packit 90a5c9
        case H2_CONF_ALT_SVC_MAX_AGE:
Packit 90a5c9
            return H2_CONFIG_GET(conf, &defconf, alt_svc_max_age);
Packit 90a5c9
        case H2_CONF_SER_HEADERS:
Packit 90a5c9
            return H2_CONFIG_GET(conf, &defconf, serialize_headers);
Packit 90a5c9
        case H2_CONF_MODERN_TLS_ONLY:
Packit 90a5c9
            return H2_CONFIG_GET(conf, &defconf, modern_tls_only);
Packit 90a5c9
        case H2_CONF_UPGRADE:
Packit 90a5c9
            return H2_CONFIG_GET(conf, &defconf, h2_upgrade);
Packit 90a5c9
        case H2_CONF_DIRECT:
Packit 90a5c9
            return H2_CONFIG_GET(conf, &defconf, h2_direct);
Packit 90a5c9
        case H2_CONF_TLS_WARMUP_SIZE:
Packit 90a5c9
            return H2_CONFIG_GET(conf, &defconf, tls_warmup_size);
Packit 90a5c9
        case H2_CONF_TLS_COOLDOWN_SECS:
Packit 90a5c9
            return H2_CONFIG_GET(conf, &defconf, tls_cooldown_secs);
Packit 90a5c9
        case H2_CONF_PUSH:
Packit 90a5c9
            return H2_CONFIG_GET(conf, &defconf, h2_push);
Packit 90a5c9
        case H2_CONF_PUSH_DIARY_SIZE:
Packit 90a5c9
            return H2_CONFIG_GET(conf, &defconf, push_diary_size);
Packit 90a5c9
        case H2_CONF_COPY_FILES:
Packit 90a5c9
            return H2_CONFIG_GET(conf, &defconf, copy_files);
Packit 90a5c9
        case H2_CONF_EARLY_HINTS:
Packit 90a5c9
            return H2_CONFIG_GET(conf, &defconf, early_hints);
Packit 90a5c9
        default:
Packit 90a5c9
            return DEF_VAL;
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
const h2_config *h2_config_sget(server_rec *s)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)ap_get_module_config(s->module_config, 
Packit 90a5c9
                                                       &http2_module);
Packit 90a5c9
    ap_assert(cfg);
Packit 90a5c9
    return cfg;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
const struct h2_priority *h2_config_get_priority(const h2_config *conf, 
Packit 90a5c9
                                                 const char *content_type)
Packit 90a5c9
{
Packit 90a5c9
    if (content_type && conf->priorities) {
Packit 90a5c9
        size_t len = strcspn(content_type, "; \t");
Packit 90a5c9
        h2_priority *prio = apr_hash_get(conf->priorities, content_type, len);
Packit 90a5c9
        return prio? prio : apr_hash_get(conf->priorities, "*", 1);
Packit 90a5c9
    }
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_set_max_streams(cmd_parms *parms,
Packit 90a5c9
                                           void *arg, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
Packit 90a5c9
    cfg->h2_max_streams = (int)apr_atoi64(value);
Packit 90a5c9
    (void)arg;
Packit 90a5c9
    if (cfg->h2_max_streams < 1) {
Packit 90a5c9
        return "value must be > 0";
Packit 90a5c9
    }
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_set_window_size(cmd_parms *parms,
Packit 90a5c9
                                           void *arg, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
Packit 90a5c9
    cfg->h2_window_size = (int)apr_atoi64(value);
Packit 90a5c9
    (void)arg;
Packit 90a5c9
    if (cfg->h2_window_size < 1024) {
Packit 90a5c9
        return "value must be >= 1024";
Packit 90a5c9
    }
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_set_min_workers(cmd_parms *parms,
Packit 90a5c9
                                           void *arg, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
Packit 90a5c9
    cfg->min_workers = (int)apr_atoi64(value);
Packit 90a5c9
    (void)arg;
Packit 90a5c9
    if (cfg->min_workers < 1) {
Packit 90a5c9
        return "value must be > 0";
Packit 90a5c9
    }
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_set_max_workers(cmd_parms *parms,
Packit 90a5c9
                                           void *arg, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
Packit 90a5c9
    cfg->max_workers = (int)apr_atoi64(value);
Packit 90a5c9
    (void)arg;
Packit 90a5c9
    if (cfg->max_workers < 1) {
Packit 90a5c9
        return "value must be > 0";
Packit 90a5c9
    }
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_set_max_worker_idle_secs(cmd_parms *parms,
Packit 90a5c9
                                                    void *arg, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
Packit 90a5c9
    cfg->max_worker_idle_secs = (int)apr_atoi64(value);
Packit 90a5c9
    (void)arg;
Packit 90a5c9
    if (cfg->max_worker_idle_secs < 1) {
Packit 90a5c9
        return "value must be > 0";
Packit 90a5c9
    }
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_set_stream_max_mem_size(cmd_parms *parms,
Packit 90a5c9
                                                   void *arg, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
Packit 90a5c9
    
Packit 90a5c9
    
Packit 90a5c9
    cfg->stream_max_mem_size = (int)apr_atoi64(value);
Packit 90a5c9
    (void)arg;
Packit 90a5c9
    if (cfg->stream_max_mem_size < 1024) {
Packit 90a5c9
        return "value must be >= 1024";
Packit 90a5c9
    }
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_add_alt_svc(cmd_parms *parms,
Packit 90a5c9
                                  void *arg, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    if (value && *value) {
Packit 90a5c9
        h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
Packit 90a5c9
        h2_alt_svc *as = h2_alt_svc_parse(value, parms->pool);
Packit 90a5c9
        if (!as) {
Packit 90a5c9
            return "unable to parse alt-svc specifier";
Packit 90a5c9
        }
Packit 90a5c9
        if (!cfg->alt_svcs) {
Packit 90a5c9
            cfg->alt_svcs = apr_array_make(parms->pool, 5, sizeof(h2_alt_svc*));
Packit 90a5c9
        }
Packit 90a5c9
        APR_ARRAY_PUSH(cfg->alt_svcs, h2_alt_svc*) = as;
Packit 90a5c9
    }
Packit 90a5c9
    (void)arg;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_set_alt_svc_max_age(cmd_parms *parms,
Packit 90a5c9
                                               void *arg, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
Packit 90a5c9
    cfg->alt_svc_max_age = (int)apr_atoi64(value);
Packit 90a5c9
    (void)arg;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_set_session_extra_files(cmd_parms *parms,
Packit 90a5c9
                                                   void *arg, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    /* deprecated, ignore */
Packit 90a5c9
    (void)arg;
Packit 90a5c9
    (void)value;
Packit 90a5c9
    ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, parms->pool, /* NO LOGNO */
Packit 90a5c9
                  "H2SessionExtraFiles is obsolete and will be ignored");
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_set_serialize_headers(cmd_parms *parms,
Packit 90a5c9
                                                 void *arg, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
Packit 90a5c9
    if (!strcasecmp(value, "On")) {
Packit 90a5c9
        cfg->serialize_headers = 1;
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(value, "Off")) {
Packit 90a5c9
        cfg->serialize_headers = 0;
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    (void)arg;
Packit 90a5c9
    return "value must be On or Off";
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_set_direct(cmd_parms *parms,
Packit 90a5c9
                                      void *arg, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
Packit 90a5c9
    if (!strcasecmp(value, "On")) {
Packit 90a5c9
        cfg->h2_direct = 1;
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(value, "Off")) {
Packit 90a5c9
        cfg->h2_direct = 0;
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    (void)arg;
Packit 90a5c9
    return "value must be On or Off";
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_set_push(cmd_parms *parms,
Packit 90a5c9
                                    void *arg, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
Packit 90a5c9
    if (!strcasecmp(value, "On")) {
Packit 90a5c9
        cfg->h2_push = 1;
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(value, "Off")) {
Packit 90a5c9
        cfg->h2_push = 0;
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    (void)arg;
Packit 90a5c9
    return "value must be On or Off";
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_add_push_priority(cmd_parms *cmd, void *_cfg,
Packit 90a5c9
                                             const char *ctype, const char *sdependency,
Packit 90a5c9
                                             const char *sweight)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)h2_config_sget(cmd->server);
Packit 90a5c9
    const char *sdefweight = "16";         /* default AFTER weight */
Packit 90a5c9
    h2_dependency dependency;
Packit 90a5c9
    h2_priority *priority;
Packit 90a5c9
    int weight;
Packit 90a5c9
    
Packit 90a5c9
    if (!*ctype) {
Packit 90a5c9
        return "1st argument must be a mime-type, like 'text/css' or '*'";
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    if (!sweight) {
Packit 90a5c9
        /* 2 args only, but which one? */
Packit 90a5c9
        if (apr_isdigit(sdependency[0])) {
Packit 90a5c9
            sweight = sdependency;
Packit 90a5c9
            sdependency = "AFTER";        /* default dependency */
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    if (!strcasecmp("AFTER", sdependency)) {
Packit 90a5c9
        dependency = H2_DEPENDANT_AFTER;
Packit 90a5c9
    } 
Packit 90a5c9
    else if (!strcasecmp("BEFORE", sdependency)) {
Packit 90a5c9
        dependency = H2_DEPENDANT_BEFORE;
Packit 90a5c9
        if (sweight) {
Packit 90a5c9
            return "dependecy 'Before' does not allow a weight";
Packit 90a5c9
        }
Packit 90a5c9
    } 
Packit 90a5c9
    else if (!strcasecmp("INTERLEAVED", sdependency)) {
Packit 90a5c9
        dependency = H2_DEPENDANT_INTERLEAVED;
Packit 90a5c9
        sdefweight = "256";        /* default INTERLEAVED weight */
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        return "dependency must be one of 'After', 'Before' or 'Interleaved'";
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    weight = (int)apr_atoi64(sweight? sweight : sdefweight);
Packit 90a5c9
    if (weight < NGHTTP2_MIN_WEIGHT) {
Packit 90a5c9
        return apr_psprintf(cmd->pool, "weight must be a number >= %d",
Packit 90a5c9
                            NGHTTP2_MIN_WEIGHT);
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    priority = apr_pcalloc(cmd->pool, sizeof(*priority));
Packit 90a5c9
    priority->dependency = dependency;
Packit 90a5c9
    priority->weight = weight;
Packit 90a5c9
    
Packit 90a5c9
    if (!cfg->priorities) {
Packit 90a5c9
        cfg->priorities = apr_hash_make(cmd->pool);
Packit 90a5c9
    }
Packit 90a5c9
    apr_hash_set(cfg->priorities, ctype, strlen(ctype), priority);
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_set_modern_tls_only(cmd_parms *parms,
Packit 90a5c9
                                               void *arg, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
Packit 90a5c9
    if (!strcasecmp(value, "On")) {
Packit 90a5c9
        cfg->modern_tls_only = 1;
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(value, "Off")) {
Packit 90a5c9
        cfg->modern_tls_only = 0;
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    (void)arg;
Packit 90a5c9
    return "value must be On or Off";
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_set_upgrade(cmd_parms *parms,
Packit 90a5c9
                                       void *arg, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
Packit 90a5c9
    if (!strcasecmp(value, "On")) {
Packit 90a5c9
        cfg->h2_upgrade = 1;
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(value, "Off")) {
Packit 90a5c9
        cfg->h2_upgrade = 0;
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    (void)arg;
Packit 90a5c9
    return "value must be On or Off";
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_set_tls_warmup_size(cmd_parms *parms,
Packit 90a5c9
                                               void *arg, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
Packit 90a5c9
    cfg->tls_warmup_size = apr_atoi64(value);
Packit 90a5c9
    (void)arg;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_set_tls_cooldown_secs(cmd_parms *parms,
Packit 90a5c9
                                                 void *arg, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
Packit 90a5c9
    cfg->tls_cooldown_secs = (int)apr_atoi64(value);
Packit 90a5c9
    (void)arg;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_set_push_diary_size(cmd_parms *parms,
Packit 90a5c9
                                               void *arg, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
Packit 90a5c9
    (void)arg;
Packit 90a5c9
    cfg->push_diary_size = (int)apr_atoi64(value);
Packit 90a5c9
    if (cfg->push_diary_size < 0) {
Packit 90a5c9
        return "value must be >= 0";
Packit 90a5c9
    }
Packit 90a5c9
    if (cfg->push_diary_size > 0 && (cfg->push_diary_size & (cfg->push_diary_size-1))) {
Packit 90a5c9
        return "value must a power of 2";
Packit 90a5c9
    }
Packit 90a5c9
    if (cfg->push_diary_size > (1 << 15)) {
Packit 90a5c9
        return "value must <= 65536";
Packit 90a5c9
    }
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_set_copy_files(cmd_parms *parms,
Packit 90a5c9
                                          void *arg, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)arg;
Packit 90a5c9
    if (!strcasecmp(value, "On")) {
Packit 90a5c9
        cfg->copy_files = 1;
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(value, "Off")) {
Packit 90a5c9
        cfg->copy_files = 0;
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    (void)arg;
Packit 90a5c9
    return "value must be On or Off";
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static void add_push(apr_pool_t *pool, h2_config *conf, h2_push_res *push)
Packit 90a5c9
{
Packit 90a5c9
    h2_push_res *new;
Packit 90a5c9
    if (!conf->push_list) {
Packit 90a5c9
        conf->push_list = apr_array_make(pool, 10, sizeof(*push));
Packit 90a5c9
    }
Packit 90a5c9
    new = apr_array_push(conf->push_list);
Packit 90a5c9
    new->uri_ref = push->uri_ref;
Packit 90a5c9
    new->critical = push->critical;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_add_push_res(cmd_parms *cmd, void *dirconf,
Packit 90a5c9
                                        const char *arg1, const char *arg2,
Packit 90a5c9
                                        const char *arg3)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *dconf = (h2_config*)dirconf ;
Packit 90a5c9
    h2_config *sconf = (h2_config*)h2_config_sget(cmd->server);
Packit 90a5c9
    h2_push_res push;
Packit 90a5c9
    const char *last = arg3;
Packit 90a5c9
    
Packit 90a5c9
    memset(&push, 0, sizeof(push));
Packit 90a5c9
    if (!strcasecmp("add", arg1)) {
Packit 90a5c9
        push.uri_ref = arg2;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        push.uri_ref = arg1;
Packit 90a5c9
        last = arg2;
Packit 90a5c9
        if (arg3) {
Packit 90a5c9
            return "too many parameter";
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    if (last) {
Packit 90a5c9
        if (!strcasecmp("critical", last)) {
Packit 90a5c9
            push.critical = 1;
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            return "unknown last parameter";
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* server command? set both */
Packit 90a5c9
    if (cmd->path == NULL) {
Packit 90a5c9
        add_push(cmd->pool, sconf, &push);
Packit 90a5c9
        add_push(cmd->pool, dconf, &push);
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        add_push(cmd->pool, dconf, &push);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *h2_conf_set_early_hints(cmd_parms *parms,
Packit 90a5c9
                                           void *arg, const char *value)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
Packit 90a5c9
    if (!strcasecmp(value, "On")) {
Packit 90a5c9
        cfg->early_hints = 1;
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(value, "Off")) {
Packit 90a5c9
        cfg->early_hints = 0;
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    (void)arg;
Packit 90a5c9
    return "value must be On or Off";
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void h2_get_num_workers(server_rec *s, int *minw, int *maxw)
Packit 90a5c9
{
Packit 90a5c9
    int threads_per_child = 0;
Packit 90a5c9
    const h2_config *config = h2_config_sget(s);
Packit 90a5c9
Packit 90a5c9
    *minw = h2_config_geti(config, H2_CONF_MIN_WORKERS);
Packit 90a5c9
    *maxw = h2_config_geti(config, H2_CONF_MAX_WORKERS);    
Packit 90a5c9
    ap_mpm_query(AP_MPMQ_MAX_THREADS, &threads_per_child);
Packit 90a5c9
Packit 90a5c9
    if (*minw <= 0) {
Packit 90a5c9
        *minw = threads_per_child;
Packit 90a5c9
    }
Packit 90a5c9
    if (*maxw <= 0) {
Packit 90a5c9
        /* As a default, this seems to work quite well under mpm_event. 
Packit 90a5c9
         * For people enabling http2 under mpm_prefork, start 4 threads unless 
Packit 90a5c9
         * configured otherwise. People get unhappy if their http2 requests are 
Packit 90a5c9
         * blocking each other. */
Packit 90a5c9
        *maxw = 3 * (*minw) / 2;
Packit 90a5c9
        if (*maxw < 4) {
Packit 90a5c9
            *maxw = 4;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
#define AP_END_CMD     AP_INIT_TAKE1(NULL, NULL, NULL, RSRC_CONF, NULL)
Packit 90a5c9
Packit 90a5c9
const command_rec h2_cmds[] = {
Packit 90a5c9
    AP_INIT_TAKE1("H2MaxSessionStreams", h2_conf_set_max_streams, NULL,
Packit 90a5c9
                  RSRC_CONF, "maximum number of open streams per session"),
Packit 90a5c9
    AP_INIT_TAKE1("H2WindowSize", h2_conf_set_window_size, NULL,
Packit 90a5c9
                  RSRC_CONF, "window size on client DATA"),
Packit 90a5c9
    AP_INIT_TAKE1("H2MinWorkers", h2_conf_set_min_workers, NULL,
Packit 90a5c9
                  RSRC_CONF, "minimum number of worker threads per child"),
Packit 90a5c9
    AP_INIT_TAKE1("H2MaxWorkers", h2_conf_set_max_workers, NULL,
Packit 90a5c9
                  RSRC_CONF, "maximum number of worker threads per child"),
Packit 90a5c9
    AP_INIT_TAKE1("H2MaxWorkerIdleSeconds", h2_conf_set_max_worker_idle_secs, NULL,
Packit 90a5c9
                  RSRC_CONF, "maximum number of idle seconds before a worker shuts down"),
Packit 90a5c9
    AP_INIT_TAKE1("H2StreamMaxMemSize", h2_conf_set_stream_max_mem_size, NULL,
Packit 90a5c9
                  RSRC_CONF, "maximum number of bytes buffered in memory for a stream"),
Packit 90a5c9
    AP_INIT_TAKE1("H2AltSvc", h2_add_alt_svc, NULL,
Packit 90a5c9
                  RSRC_CONF, "adds an Alt-Svc for this server"),
Packit 90a5c9
    AP_INIT_TAKE1("H2AltSvcMaxAge", h2_conf_set_alt_svc_max_age, NULL,
Packit 90a5c9
                  RSRC_CONF, "set the maximum age (in seconds) that client can rely on alt-svc information"),
Packit 90a5c9
    AP_INIT_TAKE1("H2SerializeHeaders", h2_conf_set_serialize_headers, NULL,
Packit 90a5c9
                  RSRC_CONF, "on to enable header serialization for compatibility"),
Packit 90a5c9
    AP_INIT_TAKE1("H2ModernTLSOnly", h2_conf_set_modern_tls_only, NULL,
Packit 90a5c9
                  RSRC_CONF, "off to not impose RFC 7540 restrictions on TLS"),
Packit 90a5c9
    AP_INIT_TAKE1("H2Upgrade", h2_conf_set_upgrade, NULL,
Packit 90a5c9
                  RSRC_CONF, "on to allow HTTP/1 Upgrades to h2/h2c"),
Packit 90a5c9
    AP_INIT_TAKE1("H2Direct", h2_conf_set_direct, NULL,
Packit 90a5c9
                  RSRC_CONF, "on to enable direct HTTP/2 mode"),
Packit 90a5c9
    AP_INIT_TAKE1("H2SessionExtraFiles", h2_conf_set_session_extra_files, NULL,
Packit 90a5c9
                  RSRC_CONF, "number of extra file a session might keep open (obsolete)"),
Packit 90a5c9
    AP_INIT_TAKE1("H2TLSWarmUpSize", h2_conf_set_tls_warmup_size, NULL,
Packit 90a5c9
                  RSRC_CONF, "number of bytes on TLS connection before doing max writes"),
Packit 90a5c9
    AP_INIT_TAKE1("H2TLSCoolDownSecs", h2_conf_set_tls_cooldown_secs, NULL,
Packit 90a5c9
                  RSRC_CONF, "seconds of idle time on TLS before shrinking writes"),
Packit 90a5c9
    AP_INIT_TAKE1("H2Push", h2_conf_set_push, NULL,
Packit 90a5c9
                  RSRC_CONF, "off to disable HTTP/2 server push"),
Packit 90a5c9
    AP_INIT_TAKE23("H2PushPriority", h2_conf_add_push_priority, NULL,
Packit 90a5c9
                  RSRC_CONF, "define priority of PUSHed resources per content type"),
Packit 90a5c9
    AP_INIT_TAKE1("H2PushDiarySize", h2_conf_set_push_diary_size, NULL,
Packit 90a5c9
                  RSRC_CONF, "size of push diary"),
Packit 90a5c9
    AP_INIT_TAKE1("H2CopyFiles", h2_conf_set_copy_files, NULL,
Packit 90a5c9
                  OR_FILEINFO, "on to perform copy of file data"),
Packit 90a5c9
    AP_INIT_TAKE123("H2PushResource", h2_conf_add_push_res, NULL,
Packit 90a5c9
                   OR_FILEINFO, "add a resource to be pushed in this location/on this server."),
Packit 90a5c9
    AP_INIT_TAKE1("H2EarlyHints", h2_conf_set_early_hints, NULL,
Packit 90a5c9
                  RSRC_CONF, "on to enable interim status 103 responses"),
Packit 90a5c9
    AP_END_CMD
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
const h2_config *h2_config_rget(request_rec *r)
Packit 90a5c9
{
Packit 90a5c9
    h2_config *cfg = (h2_config *)ap_get_module_config(r->per_dir_config, 
Packit 90a5c9
                                                       &http2_module);
Packit 90a5c9
    return cfg? cfg : h2_config_sget(r->server); 
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
const h2_config *h2_config_get(conn_rec *c)
Packit 90a5c9
{
Packit 90a5c9
    h2_ctx *ctx = h2_ctx_get(c, 0);
Packit 90a5c9
    
Packit 90a5c9
    if (ctx) {
Packit 90a5c9
        if (ctx->config) {
Packit 90a5c9
            return ctx->config;
Packit 90a5c9
        }
Packit 90a5c9
        else if (ctx->server) {
Packit 90a5c9
            ctx->config = h2_config_sget(ctx->server);
Packit 90a5c9
            return ctx->config;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    return h2_config_sget(c->base_server);
Packit 90a5c9
}