diff options
author | Stefan Eissing <icing@apache.org> | 2019-01-28 11:27:08 +0100 |
---|---|---|
committer | Stefan Eissing <icing@apache.org> | 2019-01-28 11:27:08 +0100 |
commit | a721d5cc9ebed4cb3679a935f4eb2cb167a78527 (patch) | |
tree | 853bdbf0a738e075569a1bdbc90c542e28b1ca04 /modules | |
parent | fr doc rebuild. (diff) | |
download | apache2-a721d5cc9ebed4cb3679a935f4eb2cb167a78527.tar.xz apache2-a721d5cc9ebed4cb3679a935f4eb2cb167a78527.zip |
*) mod_http2: Configuration directoves H2Push and H2Upgrade can now be specified per
Location/Directory, e.g. disabling PUSH for a specific set of resources. [Stefan Eissing]
*) mod_http2: HEAD requests to some module such as mod_cgid caused the stream to
terminate improperly and cause a HTTP/2 PROTOCOL_ERROR.
Fixes <https://github.com/icing/mod_h2/issues/167>. [Michael Kaufmann]
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1852339 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules')
28 files changed, 642 insertions, 464 deletions
diff --git a/modules/http2/h2.h b/modules/http2/h2.h index 38b4019ab8..786c84b2d2 100644 --- a/modules/http2/h2.h +++ b/modules/http2/h2.h @@ -162,5 +162,6 @@ typedef int h2_stream_pri_cmp(int stream_id1, int stream_id2, void *ctx); #define H2_FILTER_DEBUG_NOTE "http2-debug" #define H2_HDR_CONFORMANCE "http2-hdr-conformance" #define H2_HDR_CONFORMANCE_UNSAFE "unsafe" +#define H2_PUSH_MODE_NOTE "http2-push-mode" #endif /* defined(__mod_h2__h2__) */ diff --git a/modules/http2/h2_alt_svc.c b/modules/http2/h2_alt_svc.c index 9ce5ad9ed2..7f44100f36 100644 --- a/modules/http2/h2_alt_svc.c +++ b/modules/http2/h2_alt_svc.c @@ -75,7 +75,7 @@ h2_alt_svc *h2_alt_svc_parse(const char *s, apr_pool_t *pool) static int h2_alt_svc_handler(request_rec *r) { - const h2_config *cfg; + apr_array_header_t *alt_svcs; int i; if (r->connection->keepalives > 0) { @@ -87,8 +87,8 @@ static int h2_alt_svc_handler(request_rec *r) return DECLINED; } - cfg = h2_config_sget(r->server); - if (r->hostname && cfg && cfg->alt_svcs && cfg->alt_svcs->nelts > 0) { + alt_svcs = h2_config_alt_svcs(r); + if (r->hostname && alt_svcs && alt_svcs->nelts > 0) { const char *alt_svc_used = apr_table_get(r->headers_in, "Alt-Svc-Used"); if (!alt_svc_used) { /* We have alt-svcs defined and client is not already using @@ -99,7 +99,7 @@ static int h2_alt_svc_handler(request_rec *r) const char *alt_svc = ""; const char *svc_ma = ""; int secure = h2_h2_is_tls(r->connection); - int ma = h2_config_geti(cfg, H2_CONF_ALT_SVC_MAX_AGE); + int ma = h2_config_rgeti(r, H2_CONF_ALT_SVC_MAX_AGE); if (ma >= 0) { svc_ma = apr_psprintf(r->pool, "; ma=%d", ma); } @@ -107,8 +107,8 @@ static int h2_alt_svc_handler(request_rec *r) "h2_alt_svc: announce %s for %s:%d", (secure? "secure" : "insecure"), r->hostname, (int)r->server->port); - for (i = 0; i < cfg->alt_svcs->nelts; ++i) { - h2_alt_svc *as = h2_alt_svc_IDX(cfg->alt_svcs, i); + for (i = 0; i < alt_svcs->nelts; ++i) { + h2_alt_svc *as = h2_alt_svc_IDX(alt_svcs, i); const char *ahost = as->host; if (ahost && !apr_strnatcasecmp(ahost, r->hostname)) { ahost = NULL; diff --git a/modules/http2/h2_config.c b/modules/http2/h2_config.c index 8bb1d1cc46..7edd2eeaaf 100644 --- a/modules/http2/h2_config.c +++ b/modules/http2/h2_config.c @@ -42,6 +42,53 @@ #define H2_CONFIG_GET(a, b, n) \ (((a)->n == DEF_VAL)? (b) : (a))->n +#define H2_CONFIG_SET(a, n, v) \ + ((a)->n = v) + +#define CONFIG_CMD_SET(cmd,dir,var,val) \ + h2_config_seti(((cmd)->path? (dir) : NULL), h2_config_sget((cmd)->server), var, val) + +#define CONFIG_CMD_SET64(cmd,dir,var,val) \ + h2_config_seti64(((cmd)->path? (dir) : NULL), h2_config_sget((cmd)->server), var, val) + +/* Apache httpd module configuration for h2. */ +typedef struct h2_config { + const char *name; + int h2_max_streams; /* max concurrent # streams (http2) */ + int h2_window_size; /* stream window size (http2) */ + int min_workers; /* min # of worker threads/child */ + int max_workers; /* max # of worker threads/child */ + int max_worker_idle_secs; /* max # of idle seconds for worker */ + int stream_max_mem_size; /* max # bytes held in memory/stream */ + apr_array_header_t *alt_svcs; /* h2_alt_svc specs for this server */ + int alt_svc_max_age; /* seconds clients can rely on alt-svc info*/ + int serialize_headers; /* Use serialized HTTP/1.1 headers for + processing, better compatibility */ + int h2_direct; /* if mod_h2 is active directly */ + int modern_tls_only; /* Accept only modern TLS in HTTP/2 connections */ + int h2_upgrade; /* Allow HTTP/1 upgrade to h2/h2c */ + apr_int64_t tls_warmup_size; /* Amount of TLS data to send before going full write size */ + int tls_cooldown_secs; /* Seconds of idle time before going back to small TLS records */ + int h2_push; /* if HTTP/2 server push is enabled */ + struct apr_hash_t *priorities;/* map of content-type to h2_priority records */ + + int push_diary_size; /* # of entries in push diary */ + int copy_files; /* if files shall be copied vs setaside on output */ + apr_array_header_t *push_list;/* list of h2_push_res configurations */ + int early_hints; /* support status code 103 */ +} h2_config; + +typedef struct h2_dir_config { + const char *name; + apr_array_header_t *alt_svcs; /* h2_alt_svc specs for this server */ + int alt_svc_max_age; /* seconds clients can rely on alt-svc info*/ + int h2_upgrade; /* Allow HTTP/1 upgrade to h2/h2c */ + int h2_push; /* if HTTP/2 server push is enabled */ + apr_array_header_t *push_list;/* list of h2_push_res configurations */ + int early_hints; /* support status code 103 */ +} h2_dir_config; + + static h2_config defconf = { "default", 100, /* max_streams */ @@ -66,17 +113,25 @@ static h2_config defconf = { 0, /* early hints, http status 103 */ }; +static h2_dir_config defdconf = { + "default", + NULL, /* no alt-svcs */ + -1, /* alt-svc max age */ + -1, /* HTTP/1 Upgrade support */ + -1, /* HTTP/2 server push enabled */ + NULL, /* push list */ + -1, /* early hints, http status 103 */ +}; + void h2_config_init(apr_pool_t *pool) { (void)pool; } -static void *h2_config_create(apr_pool_t *pool, - const char *prefix, const char *x) +void *h2_config_create_svr(apr_pool_t *pool, server_rec *s) { h2_config *conf = (h2_config *)apr_pcalloc(pool, sizeof(h2_config)); - const char *s = x? x : "unknown"; - char *name = apr_pstrcat(pool, prefix, "[", s, "]", NULL); + char *name = apr_pstrcat(pool, "srv[", s->defn_name, "]", NULL); conf->name = name; conf->h2_max_streams = DEF_VAL; @@ -101,16 +156,6 @@ static void *h2_config_create(apr_pool_t *pool, return conf; } -void *h2_config_create_svr(apr_pool_t *pool, server_rec *s) -{ - return h2_config_create(pool, "srv", s->defn_name); -} - -void *h2_config_create_dir(apr_pool_t *pool, char *x) -{ - return h2_config_create(pool, "dir", x); -} - static void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv) { h2_config *base = (h2_config *)basev; @@ -152,22 +197,47 @@ static void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv) return n; } -void *h2_config_merge_dir(apr_pool_t *pool, void *basev, void *addv) +void *h2_config_merge_svr(apr_pool_t *pool, void *basev, void *addv) { return h2_config_merge(pool, basev, addv); } -void *h2_config_merge_svr(apr_pool_t *pool, void *basev, void *addv) +void *h2_config_create_dir(apr_pool_t *pool, char *x) { - return h2_config_merge(pool, basev, addv); + h2_dir_config *conf = (h2_dir_config *)apr_pcalloc(pool, sizeof(h2_dir_config)); + const char *s = x? x : "unknown"; + char *name = apr_pstrcat(pool, "dir[", s, "]", NULL); + + conf->name = name; + conf->alt_svc_max_age = DEF_VAL; + conf->h2_upgrade = DEF_VAL; + conf->h2_push = DEF_VAL; + conf->early_hints = DEF_VAL; + return conf; } -int h2_config_geti(const h2_config *conf, h2_config_var_t var) +void *h2_config_merge_dir(apr_pool_t *pool, void *basev, void *addv) { - return (int)h2_config_geti64(conf, var); + h2_dir_config *base = (h2_dir_config *)basev; + h2_dir_config *add = (h2_dir_config *)addv; + h2_dir_config *n = (h2_dir_config *)apr_pcalloc(pool, sizeof(h2_dir_config)); + + n->name = apr_pstrcat(pool, "merged[", add->name, ", ", base->name, "]", NULL); + n->alt_svcs = add->alt_svcs? add->alt_svcs : base->alt_svcs; + n->alt_svc_max_age = H2_CONFIG_GET(add, base, alt_svc_max_age); + n->h2_upgrade = H2_CONFIG_GET(add, base, h2_upgrade); + n->h2_push = H2_CONFIG_GET(add, base, h2_push); + if (add->push_list && base->push_list) { + n->push_list = apr_array_append(pool, base->push_list, add->push_list); + } + else { + n->push_list = add->push_list? add->push_list : base->push_list; + } + n->early_hints = H2_CONFIG_GET(add, base, early_hints); + return n; } -apr_int64_t h2_config_geti64(const h2_config *conf, h2_config_var_t var) +static apr_int64_t h2_srv_config_geti64(const h2_config *conf, h2_config_var_t var) { switch(var) { case H2_CONF_MAX_STREAMS: @@ -191,7 +261,8 @@ apr_int64_t h2_config_geti64(const h2_config *conf, h2_config_var_t var) case H2_CONF_UPGRADE: return H2_CONFIG_GET(conf, &defconf, h2_upgrade); case H2_CONF_DIRECT: - return H2_CONFIG_GET(conf, &defconf, h2_direct); + return 1; + /*return H2_CONFIG_GET(conf, &defconf, h2_direct);*/ case H2_CONF_TLS_WARMUP_SIZE: return H2_CONFIG_GET(conf, &defconf, tls_warmup_size); case H2_CONF_TLS_COOLDOWN_SECS: @@ -209,7 +280,78 @@ apr_int64_t h2_config_geti64(const h2_config *conf, h2_config_var_t var) } } -const h2_config *h2_config_sget(server_rec *s) +static void h2_srv_config_seti(h2_config *conf, h2_config_var_t var, int val) +{ + switch(var) { + case H2_CONF_MAX_STREAMS: + H2_CONFIG_SET(conf, h2_max_streams, val); + break; + case H2_CONF_WIN_SIZE: + H2_CONFIG_SET(conf, h2_window_size, val); + break; + case H2_CONF_MIN_WORKERS: + H2_CONFIG_SET(conf, min_workers, val); + break; + case H2_CONF_MAX_WORKERS: + H2_CONFIG_SET(conf, max_workers, val); + break; + case H2_CONF_MAX_WORKER_IDLE_SECS: + H2_CONFIG_SET(conf, max_worker_idle_secs, val); + break; + case H2_CONF_STREAM_MAX_MEM: + H2_CONFIG_SET(conf, stream_max_mem_size, val); + break; + case H2_CONF_ALT_SVC_MAX_AGE: + H2_CONFIG_SET(conf, alt_svc_max_age, val); + break; + case H2_CONF_SER_HEADERS: + H2_CONFIG_SET(conf, serialize_headers, val); + break; + case H2_CONF_MODERN_TLS_ONLY: + H2_CONFIG_SET(conf, modern_tls_only, val); + break; + case H2_CONF_UPGRADE: + H2_CONFIG_SET(conf, h2_upgrade, val); + break; + case H2_CONF_DIRECT: + H2_CONFIG_SET(conf, h2_direct, val); + break; + case H2_CONF_TLS_WARMUP_SIZE: + H2_CONFIG_SET(conf, tls_warmup_size, val); + break; + case H2_CONF_TLS_COOLDOWN_SECS: + H2_CONFIG_SET(conf, tls_cooldown_secs, val); + break; + case H2_CONF_PUSH: + H2_CONFIG_SET(conf, h2_push, val); + break; + case H2_CONF_PUSH_DIARY_SIZE: + H2_CONFIG_SET(conf, push_diary_size, val); + break; + case H2_CONF_COPY_FILES: + H2_CONFIG_SET(conf, copy_files, val); + break; + case H2_CONF_EARLY_HINTS: + H2_CONFIG_SET(conf, early_hints, val); + break; + default: + break; + } +} + +static void h2_srv_config_seti64(h2_config *conf, h2_config_var_t var, apr_int64_t val) +{ + switch(var) { + case H2_CONF_TLS_WARMUP_SIZE: + H2_CONFIG_SET(conf, tls_warmup_size, val); + break; + default: + h2_srv_config_seti(conf, var, (int)val); + break; + } +} + +static h2_config *h2_config_sget(server_rec *s) { h2_config *cfg = (h2_config *)ap_get_module_config(s->module_config, &http2_module); @@ -217,9 +359,162 @@ const h2_config *h2_config_sget(server_rec *s) return cfg; } -const struct h2_priority *h2_config_get_priority(const h2_config *conf, - const char *content_type) +static const h2_dir_config *h2_config_rget(request_rec *r) +{ + h2_dir_config *cfg = (h2_dir_config *)ap_get_module_config(r->per_dir_config, + &http2_module); + ap_assert(cfg); + return cfg; +} + +static apr_int64_t h2_dir_config_geti64(const h2_dir_config *conf, h2_config_var_t var) +{ + switch(var) { + case H2_CONF_ALT_SVC_MAX_AGE: + return H2_CONFIG_GET(conf, &defdconf, alt_svc_max_age); + case H2_CONF_UPGRADE: + return H2_CONFIG_GET(conf, &defdconf, h2_upgrade); + case H2_CONF_PUSH: + return H2_CONFIG_GET(conf, &defdconf, h2_push); + case H2_CONF_EARLY_HINTS: + return H2_CONFIG_GET(conf, &defdconf, early_hints); + + default: + return DEF_VAL; + } +} + +static void h2_config_seti(h2_dir_config *dconf, h2_config *conf, h2_config_var_t var, int val) +{ + int set_srv = !dconf; + if (dconf) { + switch(var) { + case H2_CONF_ALT_SVC_MAX_AGE: + H2_CONFIG_SET(dconf, alt_svc_max_age, val); + break; + case H2_CONF_UPGRADE: + H2_CONFIG_SET(dconf, h2_upgrade, val); + break; + case H2_CONF_PUSH: + H2_CONFIG_SET(dconf, h2_push, val); + break; + case H2_CONF_EARLY_HINTS: + H2_CONFIG_SET(dconf, early_hints, val); + break; + default: + /* not handled in dir_conf */ + set_srv = 1; + break; + } + } + + if (set_srv) { + h2_srv_config_seti(conf, var, val); + } +} + +static void h2_config_seti64(h2_dir_config *dconf, h2_config *conf, h2_config_var_t var, apr_int64_t val) { + int set_srv = !dconf; + if (dconf) { + switch(var) { + default: + /* not handled in dir_conf */ + set_srv = 1; + break; + } + } + + if (set_srv) { + h2_srv_config_seti64(conf, var, val); + } +} + +static const h2_config *h2_config_get(conn_rec *c) +{ + h2_ctx *ctx = h2_ctx_get(c, 0); + + if (ctx) { + if (ctx->config) { + return ctx->config; + } + else if (ctx->server) { + ctx->config = h2_config_sget(ctx->server); + return ctx->config; + } + } + + return h2_config_sget(c->base_server); +} + +int h2_config_cgeti(conn_rec *c, h2_config_var_t var) +{ + return (int)h2_srv_config_geti64(h2_config_get(c), var); +} + +apr_int64_t h2_config_cgeti64(conn_rec *c, h2_config_var_t var) +{ + return h2_srv_config_geti64(h2_config_get(c), var); +} + +int h2_config_sgeti(server_rec *s, h2_config_var_t var) +{ + return (int)h2_srv_config_geti64(h2_config_sget(s), var); +} + +apr_int64_t h2_config_sgeti64(server_rec *s, h2_config_var_t var) +{ + return h2_srv_config_geti64(h2_config_sget(s), var); +} + +int h2_config_geti(request_rec *r, server_rec *s, h2_config_var_t var) +{ + return (int)h2_config_geti64(r, s, var); +} + +apr_int64_t h2_config_geti64(request_rec *r, server_rec *s, h2_config_var_t var) +{ + apr_int64_t mode = r? (int)h2_dir_config_geti64(h2_config_rget(r), var) : DEF_VAL; + return (mode != DEF_VAL)? mode : h2_config_sgeti64(s, var); +} + +int h2_config_rgeti(request_rec *r, h2_config_var_t var) +{ + return h2_config_geti(r, r->server, var); +} + +apr_int64_t h2_config_rgeti64(request_rec *r, h2_config_var_t var) +{ + return h2_config_geti64(r, r->server, var); +} + +apr_array_header_t *h2_config_push_list(request_rec *r) +{ + const h2_config *sconf; + const h2_dir_config *conf = h2_config_rget(r); + + if (conf && conf->push_list) { + return conf->push_list; + } + sconf = h2_config_sget(r->server); + return sconf? sconf->push_list : NULL; +} + +apr_array_header_t *h2_config_alt_svcs(request_rec *r) +{ + const h2_config *sconf; + const h2_dir_config *conf = h2_config_rget(r); + + if (conf && conf->alt_svcs) { + return conf->alt_svcs; + } + sconf = h2_config_sget(r->server); + return sconf? sconf->alt_svcs : NULL; +} + +const struct h2_priority *h2_cconfig_get_priority(conn_rec *c, const char *content_type) +{ + const h2_config *conf = h2_config_get(c); if (content_type && conf->priorities) { apr_ssize_t len = (apr_ssize_t)strcspn(content_type, "; \t"); h2_priority *prio = apr_hash_get(conf->priorities, content_type, len); @@ -228,166 +523,156 @@ const struct h2_priority *h2_config_get_priority(const h2_config *conf, return NULL; } -static const char *h2_conf_set_max_streams(cmd_parms *parms, - void *arg, const char *value) +static const char *h2_conf_set_max_streams(cmd_parms *cmd, + void *dirconf, const char *value) { - h2_config *cfg = (h2_config *)h2_config_sget(parms->server); - cfg->h2_max_streams = (int)apr_atoi64(value); - (void)arg; - if (cfg->h2_max_streams < 1) { + apr_int64_t ival = (int)apr_atoi64(value); + if (ival < 1) { return "value must be > 0"; } + CONFIG_CMD_SET64(cmd, dirconf, H2_CONF_MAX_STREAMS, ival); return NULL; } -static const char *h2_conf_set_window_size(cmd_parms *parms, - void *arg, const char *value) +static const char *h2_conf_set_window_size(cmd_parms *cmd, + void *dirconf, const char *value) { - h2_config *cfg = (h2_config *)h2_config_sget(parms->server); - cfg->h2_window_size = (int)apr_atoi64(value); - (void)arg; - if (cfg->h2_window_size < 1024) { + int val = (int)apr_atoi64(value); + if (val < 1024) { return "value must be >= 1024"; } + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_WIN_SIZE, val); return NULL; } -static const char *h2_conf_set_min_workers(cmd_parms *parms, - void *arg, const char *value) +static const char *h2_conf_set_min_workers(cmd_parms *cmd, + void *dirconf, const char *value) { - h2_config *cfg = (h2_config *)h2_config_sget(parms->server); - cfg->min_workers = (int)apr_atoi64(value); - (void)arg; - if (cfg->min_workers < 1) { + int val = (int)apr_atoi64(value); + if (val < 1) { return "value must be > 0"; } + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MIN_WORKERS, val); return NULL; } -static const char *h2_conf_set_max_workers(cmd_parms *parms, - void *arg, const char *value) +static const char *h2_conf_set_max_workers(cmd_parms *cmd, + void *dirconf, const char *value) { - h2_config *cfg = (h2_config *)h2_config_sget(parms->server); - cfg->max_workers = (int)apr_atoi64(value); - (void)arg; - if (cfg->max_workers < 1) { + int val = (int)apr_atoi64(value); + if (val < 1) { return "value must be > 0"; } + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MAX_WORKERS, val); return NULL; } -static const char *h2_conf_set_max_worker_idle_secs(cmd_parms *parms, - void *arg, const char *value) +static const char *h2_conf_set_max_worker_idle_secs(cmd_parms *cmd, + void *dirconf, const char *value) { - h2_config *cfg = (h2_config *)h2_config_sget(parms->server); - cfg->max_worker_idle_secs = (int)apr_atoi64(value); - (void)arg; - if (cfg->max_worker_idle_secs < 1) { + int val = (int)apr_atoi64(value); + if (val < 1) { return "value must be > 0"; } + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MAX_WORKER_IDLE_SECS, val); return NULL; } -static const char *h2_conf_set_stream_max_mem_size(cmd_parms *parms, - void *arg, const char *value) +static const char *h2_conf_set_stream_max_mem_size(cmd_parms *cmd, + void *dirconf, const char *value) { - h2_config *cfg = (h2_config *)h2_config_sget(parms->server); - - - cfg->stream_max_mem_size = (int)apr_atoi64(value); - (void)arg; - if (cfg->stream_max_mem_size < 1024) { + int val = (int)apr_atoi64(value); + if (val < 1024) { return "value must be >= 1024"; } + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_STREAM_MAX_MEM, val); return NULL; } -static const char *h2_add_alt_svc(cmd_parms *parms, - void *arg, const char *value) +static const char *h2_add_alt_svc(cmd_parms *cmd, + void *dirconf, const char *value) { if (value && *value) { - h2_config *cfg = (h2_config *)h2_config_sget(parms->server); - h2_alt_svc *as = h2_alt_svc_parse(value, parms->pool); + h2_alt_svc *as = h2_alt_svc_parse(value, cmd->pool); if (!as) { return "unable to parse alt-svc specifier"; } - if (!cfg->alt_svcs) { - cfg->alt_svcs = apr_array_make(parms->pool, 5, sizeof(h2_alt_svc*)); + + if (cmd->path) { + h2_dir_config *dcfg = (h2_dir_config *)dirconf; + if (!dcfg->alt_svcs) { + dcfg->alt_svcs = apr_array_make(cmd->pool, 5, sizeof(h2_alt_svc*)); + } + APR_ARRAY_PUSH(dcfg->alt_svcs, h2_alt_svc*) = as; + } + else { + h2_config *cfg = (h2_config *)h2_config_sget(cmd->server); + if (!cfg->alt_svcs) { + cfg->alt_svcs = apr_array_make(cmd->pool, 5, sizeof(h2_alt_svc*)); + } + APR_ARRAY_PUSH(cfg->alt_svcs, h2_alt_svc*) = as; } - APR_ARRAY_PUSH(cfg->alt_svcs, h2_alt_svc*) = as; } - (void)arg; return NULL; } -static const char *h2_conf_set_alt_svc_max_age(cmd_parms *parms, - void *arg, const char *value) +static const char *h2_conf_set_alt_svc_max_age(cmd_parms *cmd, + void *dirconf, const char *value) { - h2_config *cfg = (h2_config *)h2_config_sget(parms->server); - cfg->alt_svc_max_age = (int)apr_atoi64(value); - (void)arg; + int val = (int)apr_atoi64(value); + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_ALT_SVC_MAX_AGE, val); return NULL; } -static const char *h2_conf_set_session_extra_files(cmd_parms *parms, - void *arg, const char *value) +static const char *h2_conf_set_session_extra_files(cmd_parms *cmd, + void *dirconf, const char *value) { /* deprecated, ignore */ - (void)arg; + (void)dirconf; (void)value; - ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, parms->pool, /* NO LOGNO */ + ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, cmd->pool, /* NO LOGNO */ "H2SessionExtraFiles is obsolete and will be ignored"); return NULL; } -static const char *h2_conf_set_serialize_headers(cmd_parms *parms, - void *arg, const char *value) +static const char *h2_conf_set_serialize_headers(cmd_parms *cmd, + void *dirconf, const char *value) { - h2_config *cfg = (h2_config *)h2_config_sget(parms->server); if (!strcasecmp(value, "On")) { - cfg->serialize_headers = 1; + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_SER_HEADERS, 1); return NULL; } else if (!strcasecmp(value, "Off")) { - cfg->serialize_headers = 0; + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_SER_HEADERS, 0); return NULL; } - - (void)arg; return "value must be On or Off"; } -static const char *h2_conf_set_direct(cmd_parms *parms, - void *arg, const char *value) +static const char *h2_conf_set_direct(cmd_parms *cmd, + void *dirconf, const char *value) { - h2_config *cfg = (h2_config *)h2_config_sget(parms->server); if (!strcasecmp(value, "On")) { - cfg->h2_direct = 1; + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_DIRECT, 1); return NULL; } else if (!strcasecmp(value, "Off")) { - cfg->h2_direct = 0; + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_DIRECT, 0); return NULL; } - - (void)arg; return "value must be On or Off"; } -static const char *h2_conf_set_push(cmd_parms *parms, - void *arg, const char *value) +static const char *h2_conf_set_push(cmd_parms *cmd, void *dirconf, const char *value) { - h2_config *cfg = (h2_config *)h2_config_sget(parms->server); if (!strcasecmp(value, "On")) { - cfg->h2_push = 1; + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_PUSH, 1); return NULL; } else if (!strcasecmp(value, "Off")) { - cfg->h2_push = 0; + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_PUSH, 0); return NULL; } - - (void)arg; return "value must be On or Off"; } @@ -448,102 +733,88 @@ static const char *h2_conf_add_push_priority(cmd_parms *cmd, void *_cfg, return NULL; } -static const char *h2_conf_set_modern_tls_only(cmd_parms *parms, - void *arg, const char *value) +static const char *h2_conf_set_modern_tls_only(cmd_parms *cmd, + void *dirconf, const char *value) { - h2_config *cfg = (h2_config *)h2_config_sget(parms->server); if (!strcasecmp(value, "On")) { - cfg->modern_tls_only = 1; + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MODERN_TLS_ONLY, 1); return NULL; } else if (!strcasecmp(value, "Off")) { - cfg->modern_tls_only = 0; + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MODERN_TLS_ONLY, 0); return NULL; } - - (void)arg; return "value must be On or Off"; } -static const char *h2_conf_set_upgrade(cmd_parms *parms, - void *arg, const char *value) +static const char *h2_conf_set_upgrade(cmd_parms *cmd, + void *dirconf, const char *value) { - h2_config *cfg = (h2_config *)h2_config_sget(parms->server); if (!strcasecmp(value, "On")) { - cfg->h2_upgrade = 1; + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_UPGRADE, 1); return NULL; } else if (!strcasecmp(value, "Off")) { - cfg->h2_upgrade = 0; + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_UPGRADE, 0); return NULL; } - - (void)arg; return "value must be On or Off"; } -static const char *h2_conf_set_tls_warmup_size(cmd_parms *parms, - void *arg, const char *value) +static const char *h2_conf_set_tls_warmup_size(cmd_parms *cmd, + void *dirconf, const char *value) { - h2_config *cfg = (h2_config *)h2_config_sget(parms->server); - cfg->tls_warmup_size = apr_atoi64(value); - (void)arg; + apr_int64_t val = apr_atoi64(value); + CONFIG_CMD_SET64(cmd, dirconf, H2_CONF_TLS_WARMUP_SIZE, val); return NULL; } -static const char *h2_conf_set_tls_cooldown_secs(cmd_parms *parms, - void *arg, const char *value) +static const char *h2_conf_set_tls_cooldown_secs(cmd_parms *cmd, + void *dirconf, const char *value) { - h2_config *cfg = (h2_config *)h2_config_sget(parms->server); - cfg->tls_cooldown_secs = (int)apr_atoi64(value); - (void)arg; + apr_int64_t val = (int)apr_atoi64(value); + CONFIG_CMD_SET64(cmd, dirconf, H2_CONF_TLS_COOLDOWN_SECS, val); return NULL; } -static const char *h2_conf_set_push_diary_size(cmd_parms *parms, - void *arg, const char *value) +static const char *h2_conf_set_push_diary_size(cmd_parms *cmd, + void *dirconf, const char *value) { - h2_config *cfg = (h2_config *)h2_config_sget(parms->server); - (void)arg; - cfg->push_diary_size = (int)apr_atoi64(value); - if (cfg->push_diary_size < 0) { + int val = (int)apr_atoi64(value); + if (val < 0) { return "value must be >= 0"; } - if (cfg->push_diary_size > 0 && (cfg->push_diary_size & (cfg->push_diary_size-1))) { + if (val > 0 && (val & (val-1))) { return "value must a power of 2"; } - if (cfg->push_diary_size > (1 << 15)) { + if (val > (1 << 15)) { return "value must <= 65536"; } + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_PUSH_DIARY_SIZE, val); return NULL; } -static const char *h2_conf_set_copy_files(cmd_parms *parms, - void *arg, const char *value) +static const char *h2_conf_set_copy_files(cmd_parms *cmd, + void *dirconf, const char *value) { - h2_config *cfg = (h2_config *)arg; - - (void)parms; if (!strcasecmp(value, "On")) { - cfg->copy_files = 1; + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_COPY_FILES, 1); return NULL; } else if (!strcasecmp(value, "Off")) { - cfg->copy_files = 0; + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_COPY_FILES, 0); return NULL; } - - (void)arg; return "value must be On or Off"; } -static void add_push(apr_pool_t *pool, h2_config *conf, h2_push_res *push) +static void add_push(apr_array_header_t **plist, apr_pool_t *pool, h2_push_res *push) { h2_push_res *new; - if (!conf->push_list) { - conf->push_list = apr_array_make(pool, 10, sizeof(*push)); + if (!*plist) { + *plist = apr_array_make(pool, 10, sizeof(*push)); } - new = apr_array_push(conf->push_list); + new = apr_array_push(*plist); new->uri_ref = push->uri_ref; new->critical = push->critical; } @@ -552,8 +823,6 @@ static const char *h2_conf_add_push_res(cmd_parms *cmd, void *dirconf, const char *arg1, const char *arg2, const char *arg3) { - h2_config *dconf = (h2_config*)dirconf ; - h2_config *sconf = (h2_config*)h2_config_sget(cmd->server); h2_push_res push; const char *last = arg3; @@ -578,42 +847,38 @@ static const char *h2_conf_add_push_res(cmd_parms *cmd, void *dirconf, } } - /* server command? set both */ - if (cmd->path == NULL) { - add_push(cmd->pool, sconf, &push); - add_push(cmd->pool, dconf, &push); + if (cmd->path) { + add_push(&(((h2_dir_config*)dirconf)->push_list), cmd->pool, &push); } else { - add_push(cmd->pool, dconf, &push); + add_push(&(h2_config_sget(cmd->server)->push_list), cmd->pool, &push); } - return NULL; } -static const char *h2_conf_set_early_hints(cmd_parms *parms, - void *arg, const char *value) +static const char *h2_conf_set_early_hints(cmd_parms *cmd, + void *dirconf, const char *value) { - h2_config *cfg = (h2_config *)h2_config_sget(parms->server); - if (!strcasecmp(value, "On")) { - cfg->early_hints = 1; - return NULL; - } - else if (!strcasecmp(value, "Off")) { - cfg->early_hints = 0; - return NULL; - } + int val; + + if (!strcasecmp(value, "On")) val = 1; + else if (!strcasecmp(value, "Off")) val = 0; + else return "value must be On or Off"; - (void)arg; - return "value must be On or Off"; + CONFIG_CMD_SET(cmd, dirconf, H2_CONF_EARLY_HINTS, val); + if (cmd->path) { + ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, cmd->pool, + "H2EarlyHints = %d on path %s", val, cmd->path); + } + return NULL; } void h2_get_num_workers(server_rec *s, int *minw, int *maxw) { int threads_per_child = 0; - const h2_config *config = h2_config_sget(s); - *minw = h2_config_geti(config, H2_CONF_MIN_WORKERS); - *maxw = h2_config_geti(config, H2_CONF_MAX_WORKERS); + *minw = h2_config_sgeti(s, H2_CONF_MIN_WORKERS); + *maxw = h2_config_sgeti(s, H2_CONF_MAX_WORKERS); ap_mpm_query(AP_MPMQ_MAX_THREADS, &threads_per_child); if (*minw <= 0) { @@ -655,7 +920,7 @@ const command_rec h2_cmds[] = { AP_INIT_TAKE1("H2ModernTLSOnly", h2_conf_set_modern_tls_only, NULL, RSRC_CONF, "off to not impose RFC 7540 restrictions on TLS"), AP_INIT_TAKE1("H2Upgrade", h2_conf_set_upgrade, NULL, - RSRC_CONF, "on to allow HTTP/1 Upgrades to h2/h2c"), + RSRC_CONF|OR_AUTHCFG, "on to allow HTTP/1 Upgrades to h2/h2c"), AP_INIT_TAKE1("H2Direct", h2_conf_set_direct, NULL, RSRC_CONF, "on to enable direct HTTP/2 mode"), AP_INIT_TAKE1("H2SessionExtraFiles", h2_conf_set_session_extra_files, NULL, @@ -665,7 +930,7 @@ const command_rec h2_cmds[] = { AP_INIT_TAKE1("H2TLSCoolDownSecs", h2_conf_set_tls_cooldown_secs, NULL, RSRC_CONF, "seconds of idle time on TLS before shrinking writes"), AP_INIT_TAKE1("H2Push", h2_conf_set_push, NULL, - RSRC_CONF, "off to disable HTTP/2 server push"), + RSRC_CONF|OR_AUTHCFG, "off to disable HTTP/2 server push"), AP_INIT_TAKE23("H2PushPriority", h2_conf_add_push_priority, NULL, RSRC_CONF, "define priority of PUSHed resources per content type"), AP_INIT_TAKE1("H2PushDiarySize", h2_conf_set_push_diary_size, NULL, @@ -673,33 +938,10 @@ const command_rec h2_cmds[] = { AP_INIT_TAKE1("H2CopyFiles", h2_conf_set_copy_files, NULL, OR_FILEINFO, "on to perform copy of file data"), AP_INIT_TAKE123("H2PushResource", h2_conf_add_push_res, NULL, - OR_FILEINFO, "add a resource to be pushed in this location/on this server."), + OR_FILEINFO|OR_AUTHCFG, "add a resource to be pushed in this location/on this server."), AP_INIT_TAKE1("H2EarlyHints", h2_conf_set_early_hints, NULL, RSRC_CONF, "on to enable interim status 103 responses"), AP_END_CMD }; -const h2_config *h2_config_rget(request_rec *r) -{ - h2_config *cfg = (h2_config *)ap_get_module_config(r->per_dir_config, - &http2_module); - return cfg? cfg : h2_config_sget(r->server); -} - -const h2_config *h2_config_get(conn_rec *c) -{ - h2_ctx *ctx = h2_ctx_get(c, 0); - - if (ctx) { - if (ctx->config) { - return ctx->config; - } - else if (ctx->server) { - ctx->config = h2_config_sget(ctx->server); - return ctx->config; - } - } - - return h2_config_sget(c->base_server); -} diff --git a/modules/http2/h2_config.h b/modules/http2/h2_config.h index 17d75d6035..307ed43c27 100644 --- a/modules/http2/h2_config.h +++ b/modules/http2/h2_config.h @@ -53,33 +53,6 @@ typedef struct h2_push_res { int critical; } h2_push_res; -/* Apache httpd module configuration for h2. */ -typedef struct h2_config { - const char *name; - int h2_max_streams; /* max concurrent # streams (http2) */ - int h2_window_size; /* stream window size (http2) */ - int min_workers; /* min # of worker threads/child */ - int max_workers; /* max # of worker threads/child */ - int max_worker_idle_secs; /* max # of idle seconds for worker */ - int stream_max_mem_size; /* max # bytes held in memory/stream */ - apr_array_header_t *alt_svcs; /* h2_alt_svc specs for this server */ - int alt_svc_max_age; /* seconds clients can rely on alt-svc info*/ - int serialize_headers; /* Use serialized HTTP/1.1 headers for - processing, better compatibility */ - int h2_direct; /* if mod_h2 is active directly */ - int modern_tls_only; /* Accept only modern TLS in HTTP/2 connections */ - int h2_upgrade; /* Allow HTTP/1 upgrade to h2/h2c */ - apr_int64_t tls_warmup_size; /* Amount of TLS data to send before going full write size */ - int tls_cooldown_secs; /* Seconds of idle time before going back to small TLS records */ - int h2_push; /* if HTTP/2 server push is enabled */ - struct apr_hash_t *priorities;/* map of content-type to h2_priority records */ - - int push_diary_size; /* # of entries in push diary */ - int copy_files; /* if files shall be copied vs setaside on output */ - apr_array_header_t *push_list;/* list of h2_push_res configurations */ - int early_hints; /* support status code 103 */ -} h2_config; - void *h2_config_create_dir(apr_pool_t *pool, char *x); void *h2_config_merge_dir(apr_pool_t *pool, void *basev, void *addv); @@ -88,19 +61,37 @@ void *h2_config_merge_svr(apr_pool_t *pool, void *basev, void *addv); extern const command_rec h2_cmds[]; -const h2_config *h2_config_get(conn_rec *c); -const h2_config *h2_config_sget(server_rec *s); -const h2_config *h2_config_rget(request_rec *r); +int h2_config_geti(request_rec *r, server_rec *s, h2_config_var_t var); +apr_int64_t h2_config_geti64(request_rec *r, server_rec *s, h2_config_var_t var); -int h2_config_geti(const h2_config *conf, h2_config_var_t var); -apr_int64_t h2_config_geti64(const h2_config *conf, h2_config_var_t var); +/** + * Get the configured value for variable <var> at the given connection. + */ +int h2_config_cgeti(conn_rec *c, h2_config_var_t var); +apr_int64_t h2_config_cgeti64(conn_rec *c, h2_config_var_t var); -void h2_get_num_workers(server_rec *s, int *minw, int *maxw); +/** + * Get the configured value for variable <var> at the given server. + */ +int h2_config_sgeti(server_rec *s, h2_config_var_t var); +apr_int64_t h2_config_sgeti64(server_rec *s, h2_config_var_t var); +/** + * Get the configured value for variable <var> at the given request, + * if configured for the request location. + * Fallback to request server config otherwise. + */ +int h2_config_rgeti(request_rec *r, h2_config_var_t var); +apr_int64_t h2_config_rgeti64(request_rec *r, h2_config_var_t var); + +apr_array_header_t *h2_config_push_list(request_rec *r); +apr_array_header_t *h2_config_alt_svcs(request_rec *r); + + +void h2_get_num_workers(server_rec *s, int *minw, int *maxw); void h2_config_init(apr_pool_t *pool); -const struct h2_priority *h2_config_get_priority(const h2_config *conf, - const char *content_type); +const struct h2_priority *h2_cconfig_get_priority(conn_rec *c, const char *content_type); #endif /* __mod_h2__h2_config_h__ */ diff --git a/modules/http2/h2_conn.c b/modules/http2/h2_conn.c index fa524b4741..d29cd7e996 100644 --- a/modules/http2/h2_conn.c +++ b/modules/http2/h2_conn.c @@ -110,7 +110,6 @@ static void check_modules(int force) apr_status_t h2_conn_child_init(apr_pool_t *pool, server_rec *s) { - const h2_config *config = h2_config_sget(s); apr_status_t status = APR_SUCCESS; int minw, maxw; int max_threads_per_child = 0; @@ -130,7 +129,7 @@ apr_status_t h2_conn_child_init(apr_pool_t *pool, server_rec *s) h2_get_num_workers(s, &minw, &maxw); - idle_secs = h2_config_geti(config, H2_CONF_MAX_WORKER_IDLE_SECS); + idle_secs = h2_config_sgeti(s, H2_CONF_MAX_WORKER_IDLE_SECS); ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s, "h2_workers: min=%d max=%d, mthrpchild=%d, idle_secs=%d", minw, maxw, max_threads_per_child, idle_secs); @@ -173,9 +172,10 @@ static module *h2_conn_mpm_module(void) return mpm_module; } -apr_status_t h2_conn_setup(h2_ctx *ctx, conn_rec *c, request_rec *r) +apr_status_t h2_conn_setup(conn_rec *c, request_rec *r, server_rec *s) { h2_session *session; + h2_ctx *ctx; apr_status_t status; if (!workers) { @@ -184,24 +184,19 @@ apr_status_t h2_conn_setup(h2_ctx *ctx, conn_rec *c, request_rec *r) return APR_EGENERAL; } - if (r) { - status = h2_session_rcreate(&session, r, ctx, workers); - } - else { - status = h2_session_create(&session, c, ctx, workers); - } - - if (status == APR_SUCCESS) { + if (APR_SUCCESS == (status = h2_session_create(&session, c, r, s, workers))) { + ctx = h2_ctx_get(c, 1); h2_ctx_session_set(ctx, session); } + return status; } -apr_status_t h2_conn_run(struct h2_ctx *ctx, conn_rec *c) +apr_status_t h2_conn_run(conn_rec *c) { apr_status_t status; int mpm_state = 0; - h2_session *session = h2_ctx_session_get(ctx); + h2_session *session = h2_ctx_get_session(c); ap_assert(session); do { @@ -250,7 +245,7 @@ apr_status_t h2_conn_run(struct h2_ctx *ctx, conn_rec *c) apr_status_t h2_conn_pre_close(struct h2_ctx *ctx, conn_rec *c) { - h2_session *session = h2_ctx_session_get(ctx); + h2_session *session = h2_ctx_get_session(c); (void)c; if (session) { diff --git a/modules/http2/h2_conn.h b/modules/http2/h2_conn.h index e45ff317d7..c560405c85 100644 --- a/modules/http2/h2_conn.h +++ b/modules/http2/h2_conn.h @@ -23,21 +23,21 @@ struct h2_task; /** * Setup the connection and our context for HTTP/2 processing * - * @param ctx the http2 context to setup * @param c the connection HTTP/2 is starting on * @param r the upgrade request that still awaits an answer, optional + * @param s the server selected for this connection (can be != c->base_server) */ -apr_status_t h2_conn_setup(struct h2_ctx *ctx, conn_rec *c, request_rec *r); +apr_status_t h2_conn_setup(conn_rec *c, request_rec *r, server_rec *s); /** * Run the HTTP/2 connection in synchronous fashion. * Return when the HTTP/2 session is done * and the connection will close or a fatal error occurred. * - * @param ctx the http2 context to run + * @param c the http2 connection to run * @return APR_SUCCESS when session is done. */ -apr_status_t h2_conn_run(struct h2_ctx *ctx, conn_rec *c); +apr_status_t h2_conn_run(conn_rec *c); /** * The connection is about to close. If we have not send a GOAWAY diff --git a/modules/http2/h2_conn_io.c b/modules/http2/h2_conn_io.c index afeb22606a..f94710f5bb 100644 --- a/modules/http2/h2_conn_io.c +++ b/modules/http2/h2_conn_io.c @@ -124,21 +124,20 @@ static void h2_conn_io_bb_log(conn_rec *c, int stream_id, int level, } -apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, - const h2_config *cfg) +apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, server_rec *s) { io->c = c; io->output = apr_brigade_create(c->pool, c->bucket_alloc); io->is_tls = h2_h2_is_tls(c); io->buffer_output = io->is_tls; - io->flush_threshold = (apr_size_t)h2_config_geti64(cfg, H2_CONF_STREAM_MAX_MEM); + io->flush_threshold = (apr_size_t)h2_config_sgeti64(s, H2_CONF_STREAM_MAX_MEM); if (io->is_tls) { /* This is what we start with, * see https://issues.apache.org/jira/browse/TS-2503 */ - io->warmup_size = h2_config_geti64(cfg, H2_CONF_TLS_WARMUP_SIZE); - io->cooldown_usecs = (h2_config_geti(cfg, H2_CONF_TLS_COOLDOWN_SECS) + io->warmup_size = h2_config_sgeti64(s, H2_CONF_TLS_WARMUP_SIZE); + io->cooldown_usecs = (h2_config_sgeti(s, H2_CONF_TLS_COOLDOWN_SECS) * APR_USEC_PER_SEC); io->write_size = (io->cooldown_usecs > 0? WRITE_SIZE_INITIAL : WRITE_SIZE_MAX); diff --git a/modules/http2/h2_conn_io.h b/modules/http2/h2_conn_io.h index 2c3be1cde1..e96203cac2 100644 --- a/modules/http2/h2_conn_io.h +++ b/modules/http2/h2_conn_io.h @@ -48,8 +48,7 @@ typedef struct { apr_size_t slen; } h2_conn_io; -apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, - const struct h2_config *cfg); +apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, server_rec *s); /** * Append data to the buffered output. diff --git a/modules/http2/h2_ctx.c b/modules/http2/h2_ctx.c index d5ccc24dd6..095f3554b6 100644 --- a/modules/http2/h2_ctx.c +++ b/modules/http2/h2_ctx.c @@ -29,8 +29,8 @@ static h2_ctx *h2_ctx_create(const conn_rec *c) { h2_ctx *ctx = apr_pcalloc(c->pool, sizeof(h2_ctx)); ap_assert(ctx); + h2_ctx_server_update(ctx, c->base_server); ap_set_module_config(c->conn_config, &http2_module, ctx); - h2_ctx_server_set(ctx, c->base_server); return ctx; } @@ -79,8 +79,9 @@ h2_ctx *h2_ctx_protocol_set(h2_ctx *ctx, const char *proto) return ctx; } -h2_session *h2_ctx_session_get(h2_ctx *ctx) +h2_session *h2_ctx_get_session(conn_rec *c) { + h2_ctx *ctx = h2_ctx_get(c, 0); return ctx? ctx->session : NULL; } @@ -89,33 +90,17 @@ void h2_ctx_session_set(h2_ctx *ctx, struct h2_session *session) ctx->session = session; } -server_rec *h2_ctx_server_get(h2_ctx *ctx) +h2_ctx *h2_ctx_server_update(h2_ctx *ctx, server_rec *s) { - return ctx? ctx->server : NULL; -} - -h2_ctx *h2_ctx_server_set(h2_ctx *ctx, server_rec *s) -{ - ctx->server = s; + if (ctx->server != s) { + ctx->server = s; + } return ctx; } -int h2_ctx_is_task(h2_ctx *ctx) -{ - return ctx && ctx->task; -} - -h2_task *h2_ctx_get_task(h2_ctx *ctx) +h2_task *h2_ctx_get_task(conn_rec *c) { + h2_ctx *ctx = h2_ctx_get(c, 0); return ctx? ctx->task : NULL; } -h2_task *h2_ctx_cget_task(conn_rec *c) -{ - return h2_ctx_get_task(h2_ctx_get(c, 0)); -} - -h2_task *h2_ctx_rget_task(request_rec *r) -{ - return h2_ctx_get_task(h2_ctx_rget(r)); -} diff --git a/modules/http2/h2_ctx.h b/modules/http2/h2_ctx.h index cb111c9eaa..417ef36377 100644 --- a/modules/http2/h2_ctx.h +++ b/modules/http2/h2_ctx.h @@ -56,12 +56,11 @@ h2_ctx *h2_ctx_create_for(const conn_rec *c, struct h2_task *task); */ h2_ctx *h2_ctx_protocol_set(h2_ctx *ctx, const char *proto); -/* Set the server_rec relevant for this context. +/* Update the server_rec relevant for this context. A server for + * a connection may change during SNI handling, for example. */ -h2_ctx *h2_ctx_server_set(h2_ctx *ctx, server_rec *s); -server_rec *h2_ctx_server_get(h2_ctx *ctx); +h2_ctx *h2_ctx_server_update(h2_ctx *ctx, server_rec *s); -struct h2_session *h2_ctx_session_get(h2_ctx *ctx); void h2_ctx_session_set(h2_ctx *ctx, struct h2_session *session); /** @@ -69,10 +68,8 @@ void h2_ctx_session_set(h2_ctx *ctx, struct h2_session *session); */ const char *h2_ctx_protocol_get(const conn_rec *c); -int h2_ctx_is_task(h2_ctx *ctx); +struct h2_session *h2_ctx_get_session(conn_rec *c); +struct h2_task *h2_ctx_get_task(conn_rec *c); -struct h2_task *h2_ctx_get_task(h2_ctx *ctx); -struct h2_task *h2_ctx_cget_task(conn_rec *c); -struct h2_task *h2_ctx_rget_task(request_rec *r); #endif /* defined(__mod_h2__h2_ctx__) */ diff --git a/modules/http2/h2_filter.c b/modules/http2/h2_filter.c index 5bda60bf58..5fd237f393 100644 --- a/modules/http2/h2_filter.c +++ b/modules/http2/h2_filter.c @@ -313,8 +313,7 @@ static void add_settings(apr_bucket_brigade *bb, h2_session *s, int last) bbout(bb, " \"settings\": {\n"); bbout(bb, " \"SETTINGS_MAX_CONCURRENT_STREAMS\": %d,\n", m->max_streams); bbout(bb, " \"SETTINGS_MAX_FRAME_SIZE\": %d,\n", 16*1024); - bbout(bb, " \"SETTINGS_INITIAL_WINDOW_SIZE\": %d,\n", - h2_config_geti(s->config, H2_CONF_WIN_SIZE)); + bbout(bb, " \"SETTINGS_INITIAL_WINDOW_SIZE\": %d,\n", h2_config_sgeti(s->s, H2_CONF_WIN_SIZE)); bbout(bb, " \"SETTINGS_ENABLE_PUSH\": %d\n", h2_session_push_enabled(s)); bbout(bb, " }%s\n", last? "" : ","); } @@ -496,7 +495,6 @@ static apr_status_t status_event(void *ctx, h2_bucket_event event, int h2_filter_h2_status_handler(request_rec *r) { - h2_ctx *ctx = h2_ctx_rget(r); conn_rec *c = r->connection; h2_task *task; apr_bucket_brigade *bb; @@ -510,7 +508,7 @@ int h2_filter_h2_status_handler(request_rec *r) return DECLINED; } - task = ctx? h2_ctx_get_task(ctx) : NULL; + task = h2_ctx_get_task(r->connection); if (task) { if ((status = ap_discard_request_body(r)) != OK) { diff --git a/modules/http2/h2_from_h1.c b/modules/http2/h2_from_h1.c index 20645d9f2d..edb1d8e1b5 100644 --- a/modules/http2/h2_from_h1.c +++ b/modules/http2/h2_from_h1.c @@ -594,18 +594,20 @@ apr_status_t h2_filter_headers_out(ap_filter_t *f, apr_bucket_brigade *bb) } } - if (r->header_only) { + if (r->header_only || AP_STATUS_IS_HEADER_ONLY(r->status)) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c, - "h2_task(%s): header_only, cleanup output brigade", + "h2_task(%s): headers only, cleanup output brigade", task->id); b = body_bucket? body_bucket : APR_BRIGADE_FIRST(bb); while (b != APR_BRIGADE_SENTINEL(bb)) { next = APR_BUCKET_NEXT(b); if (APR_BUCKET_IS_EOS(b) || AP_BUCKET_IS_EOR(b)) { break; - } - APR_BUCKET_REMOVE(b); - apr_bucket_destroy(b); + } + if (!H2_BUCKET_IS_HEADERS(b)) { + APR_BUCKET_REMOVE(b); + apr_bucket_destroy(b); + } b = next; } } diff --git a/modules/http2/h2_h2.c b/modules/http2/h2_h2.c index 5580cefde1..4ff1d51d84 100644 --- a/modules/http2/h2_h2.c +++ b/modules/http2/h2_h2.c @@ -463,19 +463,18 @@ int h2_h2_is_tls(conn_rec *c) return opt_ssl_is_https && opt_ssl_is_https(c); } -int h2_is_acceptable_connection(conn_rec *c, int require_all) +int h2_is_acceptable_connection(conn_rec *c, request_rec *r, int require_all) { int is_tls = h2_h2_is_tls(c); - const h2_config *cfg = h2_config_get(c); - if (is_tls && h2_config_geti(cfg, H2_CONF_MODERN_TLS_ONLY) > 0) { + if (is_tls && h2_config_cgeti(c, H2_CONF_MODERN_TLS_ONLY) > 0) { /* Check TLS connection for modern TLS parameters, as defined in * RFC 7540 and https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility */ apr_pool_t *pool = c->pool; server_rec *s = c->base_server; char *val; - + if (!opt_ssl_var_lookup) { /* unable to check */ return 0; @@ -521,26 +520,22 @@ int h2_is_acceptable_connection(conn_rec *c, int require_all) return 1; } -int h2_allows_h2_direct(conn_rec *c) +static int h2_allows_h2_direct(conn_rec *c) { - const h2_config *cfg = h2_config_get(c); int is_tls = h2_h2_is_tls(c); const char *needed_protocol = is_tls? "h2" : "h2c"; - int h2_direct = h2_config_geti(cfg, H2_CONF_DIRECT); + int h2_direct = h2_config_cgeti(c, H2_CONF_DIRECT); if (h2_direct < 0) { h2_direct = is_tls? 0 : 1; } - return (h2_direct - && ap_is_allowed_protocol(c, NULL, NULL, needed_protocol)); + return (h2_direct && ap_is_allowed_protocol(c, NULL, NULL, needed_protocol)); } -int h2_allows_h2_upgrade(conn_rec *c) +int h2_allows_h2_upgrade(request_rec *r) { - const h2_config *cfg = h2_config_get(c); - int h2_upgrade = h2_config_geti(cfg, H2_CONF_UPGRADE); - - return h2_upgrade > 0 || (h2_upgrade < 0 && !h2_h2_is_tls(c)); + int h2_upgrade = h2_config_rgeti(r, H2_CONF_UPGRADE); + return h2_upgrade > 0 || (h2_upgrade < 0 && !h2_h2_is_tls(r->connection)); } /******************************************************************************* @@ -581,14 +576,17 @@ int h2_h2_process_conn(conn_rec* c) { apr_status_t status; h2_ctx *ctx; + server_rec *s; if (c->master) { return DECLINED; } ctx = h2_ctx_get(c, 0); + s = ctx? ctx->server : c->base_server; + ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, process_conn"); - if (h2_ctx_is_task(ctx)) { + if (ctx && ctx->task) { /* our stream pseudo connection */ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, task, declined"); return DECLINED; @@ -601,19 +599,19 @@ int h2_h2_process_conn(conn_rec* c) ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, process_conn, " "new connection using protocol '%s', direct=%d, " "tls acceptable=%d", proto, h2_allows_h2_direct(c), - h2_is_acceptable_connection(c, 1)); + h2_is_acceptable_connection(c, NULL, 1)); } if (!strcmp(AP_PROTOCOL_HTTP1, proto) && h2_allows_h2_direct(c) - && h2_is_acceptable_connection(c, 1)) { + && h2_is_acceptable_connection(c, NULL, 1)) { /* Fresh connection still is on http/1.1 and H2Direct is enabled. * Otherwise connection is in a fully acceptable state. * -> peek at the first 24 incoming bytes */ apr_bucket_brigade *temp; - char *s = NULL; - apr_size_t slen; + char *peek = NULL; + apr_size_t peeklen; temp = apr_brigade_create(c->pool, c->bucket_alloc); status = ap_get_brigade(c->input_filters, temp, @@ -626,8 +624,8 @@ int h2_h2_process_conn(conn_rec* c) return DECLINED; } - apr_brigade_pflatten(temp, &s, &slen, c->pool); - if ((slen >= 24) && !memcmp(H2_MAGIC_TOKEN, s, 24)) { + apr_brigade_pflatten(temp, &peek, &peeklen, c->pool); + if ((peeklen >= 24) && !memcmp(H2_MAGIC_TOKEN, peek, 24)) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, direct mode detected"); if (!ctx) { @@ -638,7 +636,7 @@ int h2_h2_process_conn(conn_rec* c) else if (APLOGctrace2(c)) { ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, not detected in %d bytes(base64): %s", - (int)slen, h2_util_base64url_encode(s, slen, c->pool)); + (int)peeklen, h2_util_base64url_encode(peek, peeklen, c->pool)); } apr_brigade_destroy(temp); @@ -647,15 +645,16 @@ int h2_h2_process_conn(conn_rec* c) if (ctx) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "process_conn"); - if (!h2_ctx_session_get(ctx)) { - status = h2_conn_setup(ctx, c, NULL); + + if (!h2_ctx_get_session(c)) { + status = h2_conn_setup(c, NULL, s); ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, c, "conn_setup"); if (status != APR_SUCCESS) { h2_ctx_clear(c); return !OK; } } - h2_conn_run(ctx, c); + h2_conn_run(c); return OK; } @@ -684,16 +683,17 @@ static int h2_h2_pre_close_conn(conn_rec *c) static void check_push(request_rec *r, const char *tag) { - const h2_config *conf = h2_config_rget(r); - if (!r->expecting_100 - && conf && conf->push_list && conf->push_list->nelts > 0) { + apr_array_header_t *push_list = h2_config_push_list(r); + + if (!r->expecting_100 && push_list && push_list->nelts > 0) { int i, old_status; const char *old_line; + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "%s, early announcing %d resources for push", - tag, conf->push_list->nelts); - for (i = 0; i < conf->push_list->nelts; ++i) { - h2_push_res *push = &APR_ARRAY_IDX(conf->push_list, i, h2_push_res); + tag, push_list->nelts); + for (i = 0; i < push_list->nelts; ++i) { + h2_push_res *push = &APR_ARRAY_IDX(push_list, i, h2_push_res); apr_table_add(r->headers_out, "Link", apr_psprintf(r->pool, "<%s>; rel=preload%s", push->uri_ref, push->critical? "; critical" : "")); @@ -712,8 +712,7 @@ static int h2_h2_post_read_req(request_rec *r) { /* slave connection? */ if (r->connection->master) { - h2_ctx *ctx = h2_ctx_rget(r); - struct h2_task *task = h2_ctx_get_task(ctx); + struct h2_task *task = h2_ctx_get_task(r->connection); /* This hook will get called twice on internal redirects. Take care * that we manipulate filters only once. */ if (task && !task->filters_set) { @@ -746,12 +745,10 @@ static int h2_h2_late_fixups(request_rec *r) { /* slave connection? */ if (r->connection->master) { - h2_ctx *ctx = h2_ctx_rget(r); - struct h2_task *task = h2_ctx_get_task(ctx); + struct h2_task *task = h2_ctx_get_task(r->connection); if (task) { /* check if we copy vs. setaside files in this location */ - task->output.copy_files = h2_config_geti(h2_config_rget(r), - H2_CONF_COPY_FILES); + task->output.copy_files = h2_config_rgeti(r, H2_CONF_COPY_FILES); if (task->output.copy_files) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, task->c, "h2_slave_out(%s): copy_files on", task->id); diff --git a/modules/http2/h2_h2.h b/modules/http2/h2_h2.h index 367823d344..339e898a10 100644 --- a/modules/http2/h2_h2.h +++ b/modules/http2/h2_h2.h @@ -57,23 +57,15 @@ void h2_h2_register_hooks(void); * the handshake is still ongoing. * @return != 0 iff connection requirements are met */ -int h2_is_acceptable_connection(conn_rec *c, int require_all); - -/** - * Check if the "direct" HTTP/2 mode of protocol handling is enabled - * for the given connection. - * @param c the connection to check - * @return != 0 iff direct mode is enabled - */ -int h2_allows_h2_direct(conn_rec *c); +int h2_is_acceptable_connection(conn_rec *c, request_rec *r, int require_all); /** * Check if the "Upgrade" HTTP/1.1 mode of protocol switching is enabled - * for the given connection. - * @param c the connection to check + * for the given request. + * @param r the request to check * @return != 0 iff Upgrade switching is enabled */ -int h2_allows_h2_upgrade(conn_rec *c); +int h2_allows_h2_upgrade(request_rec *r); #endif /* defined(__mod_h2__h2_h2__) */ diff --git a/modules/http2/h2_headers.c b/modules/http2/h2_headers.c index 8b7add6230..1f7a8ede73 100644 --- a/modules/http2/h2_headers.c +++ b/modules/http2/h2_headers.c @@ -28,6 +28,7 @@ #include "h2_private.h" #include "h2_h2.h" +#include "h2_config.h" #include "h2_util.h" #include "h2_request.h" #include "h2_headers.h" @@ -141,8 +142,10 @@ h2_headers *h2_headers_rcreate(request_rec *r, int status, } } if (is_unsafe(r->server)) { - apr_table_setn(headers->notes, H2_HDR_CONFORMANCE, - H2_HDR_CONFORMANCE_UNSAFE); + apr_table_setn(headers->notes, H2_HDR_CONFORMANCE, H2_HDR_CONFORMANCE_UNSAFE); + } + if (h2_config_rgeti(r, H2_CONF_PUSH) == 0 && h2_config_sgeti(r->server, H2_CONF_PUSH) != 0) { + apr_table_setn(headers->notes, H2_PUSH_MODE_NOTE, "0"); } return headers; } diff --git a/modules/http2/h2_mplx.c b/modules/http2/h2_mplx.c index b0d075ea61..b828442976 100644 --- a/modules/http2/h2_mplx.c +++ b/modules/http2/h2_mplx.c @@ -151,25 +151,19 @@ static void stream_cleanup(h2_mplx *m, h2_stream *stream) * their HTTP/1 cousins, the separate allocator seems to work better * than protecting a shared h2_session one with an own lock. */ -h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *parent, - const h2_config *conf, +h2_mplx *h2_mplx_create(conn_rec *c, server_rec *s, apr_pool_t *parent, h2_workers *workers) { apr_status_t status = APR_SUCCESS; apr_allocator_t *allocator; apr_thread_mutex_t *mutex; h2_mplx *m; - h2_ctx *ctx = h2_ctx_get(c, 0); - ap_assert(conf); m = apr_pcalloc(parent, sizeof(h2_mplx)); if (m) { m->id = c->id; m->c = c; - m->s = (ctx? h2_ctx_server_get(ctx) : NULL); - if (!m->s) { - m->s = c->base_server; - } + m->s = s; /* We create a pool with its own allocator to be used for * processing slave connections. This is the only way to have the @@ -210,8 +204,8 @@ h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *parent, return NULL; } - m->max_streams = h2_config_geti(conf, H2_CONF_MAX_STREAMS); - m->stream_max_mem = h2_config_geti(conf, H2_CONF_STREAM_MAX_MEM); + m->max_streams = h2_config_sgeti(s, H2_CONF_MAX_STREAMS); + m->stream_max_mem = h2_config_sgeti(s, H2_CONF_STREAM_MAX_MEM); m->streams = h2_ihash_create(m->pool, offsetof(h2_stream,id)); m->sredo = h2_ihash_create(m->pool, offsetof(h2_stream,id)); @@ -327,8 +321,7 @@ static int stream_destroy_iter(void *ctx, void *val) && !task->rst_error); } - task->c = NULL; - if (reuse_slave) { + if (reuse_slave && slave->keepalive == AP_CONN_KEEPALIVE) { h2_beam_log(task->output.beam, m->c, APLOG_DEBUG, APLOGNO(03385) "h2_task_destroy, reuse slave"); h2_task_destroy(task); @@ -795,6 +788,8 @@ static void task_done(h2_mplx *m, h2_task *task, h2_req_engine *ngn) /* this task was handed over to an engine for processing * and the original worker has finished. That means the * engine may start processing now. */ + ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c, + "h2_mplx(%ld): task(%s) done (frozen)", m->id, task->id); h2_task_thaw(task); apr_thread_cond_broadcast(m->task_thawed); return; @@ -849,18 +844,24 @@ static void task_done(h2_mplx *m, h2_task *task, h2_req_engine *ngn) m->id, m->limit_active); } } - + + ap_assert(task->done_done == 0); + stream = h2_ihash_get(m->streams, task->stream_id); if (stream) { /* stream not done yet. */ if (!m->aborted && h2_ihash_get(m->sredo, stream->id)) { /* reset and schedule again */ + task->worker_done = 0; h2_task_redo(task); h2_ihash_remove(m->sredo, stream->id); h2_iq_add(m->q, stream->id, NULL, NULL); + ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, m->c, + H2_STRM_MSG(stream, "redo, added to q")); } else { /* stream not cleaned up, stay around */ + task->done_done = 1; ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c, H2_STRM_MSG(stream, "task_done, stream open")); if (stream->input) { @@ -873,6 +874,7 @@ static void task_done(h2_mplx *m, h2_task *task, h2_req_engine *ngn) } else if ((stream = h2_ihash_get(m->shold, task->stream_id)) != NULL) { /* stream is done, was just waiting for this. */ + task->done_done = 1; ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c, H2_STRM_MSG(stream, "task_done, in hold")); if (stream->input) { @@ -1132,7 +1134,7 @@ apr_status_t h2_mplx_req_engine_push(const char *ngn_type, h2_task *task; h2_stream *stream; - task = h2_ctx_rget_task(r); + task = h2_ctx_get_task(r->connection); if (!task) { return APR_ECONNABORTED; } @@ -1196,11 +1198,12 @@ apr_status_t h2_mplx_req_engine_pull(h2_req_engine *ngn, void h2_mplx_req_engine_done(h2_req_engine *ngn, conn_rec *r_conn, apr_status_t status) { - h2_task *task = h2_ctx_cget_task(r_conn); + h2_task *task = h2_ctx_get_task(r_conn); if (task) { h2_mplx *m = task->mplx; h2_stream *stream; + int task_hosting_engine = (task->engine != NULL); H2_MPLX_ENTER_ALWAYS(m); @@ -1212,13 +1215,13 @@ void h2_mplx_req_engine_done(h2_req_engine *ngn, conn_rec *r_conn, if (status != APR_SUCCESS && stream && h2_task_can_redo(task) && !h2_ihash_get(m->sredo, stream->id)) { + ap_log_cerror(APLOG_MARK, APLOG_INFO, status, m->c, + "h2_mplx(%ld): task %s added to redo", m->id, task->id); h2_ihash_add(m->sredo, stream); } - if (task->engine) { - /* cannot report that as done until engine returns */ - } - else { + /* cannot report that until hosted engine returns */ + if (!task_hosting_engine) { task_done(m, task, ngn); } diff --git a/modules/http2/h2_mplx.h b/modules/http2/h2_mplx.h index 2890b98579..b5db224a27 100644 --- a/modules/http2/h2_mplx.h +++ b/modules/http2/h2_mplx.h @@ -111,8 +111,7 @@ apr_status_t h2_mplx_child_init(apr_pool_t *pool, server_rec *s); * Create the multiplexer for the given HTTP2 session. * Implicitly has reference count 1. */ -h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *master, - const struct h2_config *conf, +h2_mplx *h2_mplx_create(conn_rec *c, server_rec *s, apr_pool_t *master, struct h2_workers *workers); /** diff --git a/modules/http2/h2_ngn_shed.c b/modules/http2/h2_ngn_shed.c index 8b532711d7..39582592ce 100644 --- a/modules/http2/h2_ngn_shed.c +++ b/modules/http2/h2_ngn_shed.c @@ -161,7 +161,7 @@ apr_status_t h2_ngn_shed_push_request(h2_ngn_shed *shed, const char *ngn_type, http2_req_engine_init *einit) { h2_req_engine *ngn; - h2_task *task = h2_ctx_rget_task(r); + h2_task *task = h2_ctx_get_task(r->connection); ap_assert(task); ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, shed->c, diff --git a/modules/http2/h2_request.c b/modules/http2/h2_request.c index 5858f1db96..d3341bb4da 100644 --- a/modules/http2/h2_request.c +++ b/modules/http2/h2_request.c @@ -85,8 +85,7 @@ apr_status_t h2_request_rcreate(h2_request **preq, apr_pool_t *pool, req->path = path; req->headers = apr_table_make(pool, 10); if (r->server) { - req->serialize = h2_config_geti(h2_config_sget(r->server), - H2_CONF_SER_HEADERS); + req->serialize = h2_config_rgeti(r, H2_CONF_SER_HEADERS); } x.pool = pool; diff --git a/modules/http2/h2_session.c b/modules/http2/h2_session.c index df2c8c9b9e..2eda330de6 100644 --- a/modules/http2/h2_session.c +++ b/modules/http2/h2_session.c @@ -757,9 +757,8 @@ static apr_status_t session_pool_cleanup(void *data) { conn_rec *c = data; h2_session *session; - h2_ctx *ctx = h2_ctx_get(c, 0); - if (ctx && (session = h2_ctx_session_get(ctx))) { + if ((session = h2_ctx_get_session(c))) { /* if the session is still there, now is the last chance * to perform cleanup. Normally, cleanup should have happened * earlier in the connection pre_close. Main reason is that @@ -775,11 +774,8 @@ static apr_status_t session_pool_cleanup(void *data) return APR_SUCCESS; } -static apr_status_t h2_session_create_int(h2_session **psession, - conn_rec *c, - request_rec *r, - h2_ctx *ctx, - h2_workers *workers) +apr_status_t h2_session_create(h2_session **psession, conn_rec *c, request_rec *r, + server_rec *s, h2_workers *workers) { nghttp2_session_callbacks *callbacks = NULL; nghttp2_option *options = NULL; @@ -820,19 +816,16 @@ static apr_status_t h2_session_create_int(h2_session **psession, session->id = c->id; session->c = c; session->r = r; - session->s = h2_ctx_server_get(ctx); + session->s = s; session->pool = pool; - session->config = h2_config_sget(session->s); session->workers = workers; session->state = H2_SESSION_ST_INIT; session->local.accepting = 1; session->remote.accepting = 1; - session->max_stream_count = h2_config_geti(session->config, - H2_CONF_MAX_STREAMS); - session->max_stream_mem = h2_config_geti(session->config, - H2_CONF_STREAM_MAX_MEM); + session->max_stream_count = h2_config_sgeti(s, H2_CONF_MAX_STREAMS); + session->max_stream_mem = h2_config_sgeti(s, H2_CONF_STREAM_MAX_MEM); status = apr_thread_cond_create(&session->iowait, session->pool); if (status != APR_SUCCESS) { @@ -862,14 +855,13 @@ static apr_status_t h2_session_create_int(h2_session **psession, session->monitor->on_state_event = on_stream_state_event; session->monitor->on_event = on_stream_event; - session->mplx = h2_mplx_create(c, session->pool, session->config, - workers); + session->mplx = h2_mplx_create(c, s, session->pool, workers); /* connection input filter that feeds the session */ session->cin = h2_filter_cin_create(session); ap_add_input_filter("H2_IN", session->cin, r, c); - h2_conn_io_init(&session->io, c, session->config); + h2_conn_io_init(&session->io, c, s); session->bbtmp = apr_brigade_create(session->pool, c->bucket_alloc); status = init_callbacks(c, &callbacks); @@ -888,8 +880,7 @@ static apr_status_t h2_session_create_int(h2_session **psession, apr_pool_destroy(pool); return status; } - nghttp2_option_set_peer_max_concurrent_streams( - options, (uint32_t)session->max_stream_count); + nghttp2_option_set_peer_max_concurrent_streams(options, (uint32_t)session->max_stream_count); /* We need to handle window updates ourself, otherwise we * get flooded by nghttp2. */ nghttp2_option_set_no_auto_window_update(options, 1); @@ -907,7 +898,7 @@ static apr_status_t h2_session_create_int(h2_session **psession, return APR_ENOMEM; } - n = h2_config_geti(session->config, H2_CONF_PUSH_DIARY_SIZE); + n = h2_config_sgeti(s, H2_CONF_PUSH_DIARY_SIZE); session->push_diary = h2_push_diary_create(session->pool, n); if (APLOGcdebug(c)) { @@ -924,22 +915,11 @@ static apr_status_t h2_session_create_int(h2_session **psession, (int)session->push_diary->N); } - apr_pool_pre_cleanup_register(pool, c, session_pool_cleanup); + apr_pool_pre_cleanup_register(pool, c, session_pool_cleanup); + return APR_SUCCESS; } -apr_status_t h2_session_create(h2_session **psession, - conn_rec *c, h2_ctx *ctx, h2_workers *workers) -{ - return h2_session_create_int(psession, c, NULL, ctx, workers); -} - -apr_status_t h2_session_rcreate(h2_session **psession, - request_rec *r, h2_ctx *ctx, h2_workers *workers) -{ - return h2_session_create_int(psession, r->connection, r, ctx, workers); -} - static apr_status_t h2_session_start(h2_session *session, int *rv) { apr_status_t status = APR_SUCCESS; @@ -1004,7 +984,7 @@ static apr_status_t h2_session_start(h2_session *session, int *rv) settings[slen].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; settings[slen].value = (uint32_t)session->max_stream_count; ++slen; - win_size = h2_config_geti(session->config, H2_CONF_WIN_SIZE); + win_size = h2_config_sgeti(session->s, H2_CONF_WIN_SIZE); if (win_size != H2_INITIAL_WINDOW_SIZE) { settings[slen].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; settings[slen].value = win_size; @@ -1280,7 +1260,7 @@ int h2_session_push_enabled(h2_session *session) { /* iff we can and they can and want */ return (session->remote.accepting /* remote GOAWAY received */ - && h2_config_geti(session->config, H2_CONF_PUSH) + && h2_config_sgeti(session->s, H2_CONF_PUSH) && nghttp2_session_get_remote_settings(session->ngh2, NGHTTP2_SETTINGS_ENABLE_PUSH)); } @@ -1324,6 +1304,7 @@ static apr_status_t on_stream_headers(h2_session *session, h2_stream *stream, int eos) { apr_status_t status = APR_SUCCESS; + const char *s; int rv = 0; ap_assert(session); @@ -1391,8 +1372,12 @@ static apr_status_t on_stream_headers(h2_session *session, h2_stream *stream, && (headers->status < 400) && (headers->status != 304) && h2_session_push_enabled(session)) { - - h2_stream_submit_pushes(stream, headers); + /* PUSH is possibe and enabled on server, unless the request + * denies it, submit resources to push */ + s = apr_table_get(headers->notes, H2_PUSH_MODE_NOTE); + if (!s || strcmp(s, "0")) { + h2_stream_submit_pushes(stream, headers); + } } if (!stream->pref_priority) { @@ -1414,7 +1399,7 @@ static apr_status_t on_stream_headers(h2_session *session, h2_stream *stream, } if (headers->status == 103 - && !h2_config_geti(session->config, H2_CONF_EARLY_HINTS)) { + && !h2_config_sgeti(session->s, H2_CONF_EARLY_HINTS)) { /* suppress sending this to the client, it might have triggered * pushes and served its purpose nevertheless */ rv = 0; @@ -2089,7 +2074,7 @@ apr_status_t h2_session_process(h2_session *session, int async) switch (session->state) { case H2_SESSION_ST_INIT: ap_update_child_status_from_conn(c->sbh, SERVER_BUSY_READ, c); - if (!h2_is_acceptable_connection(c, 1)) { + if (!h2_is_acceptable_connection(c, session->r, 1)) { update_child_status(session, SERVER_BUSY_READ, "inadequate security"); h2_session_shutdown(session, diff --git a/modules/http2/h2_session.h b/modules/http2/h2_session.h index 29b18c8501..764da8a21d 100644 --- a/modules/http2/h2_session.h +++ b/modules/http2/h2_session.h @@ -80,7 +80,6 @@ typedef struct h2_session { request_rec *r; /* the request that started this in case * of 'h2c', NULL otherwise */ server_rec *s; /* server/vhost we're starting on */ - const struct h2_config *config; /* Relevant config for this session */ apr_pool_t *pool; /* pool to use in session */ struct h2_mplx *mplx; /* multiplexer for stream data */ struct h2_workers *workers; /* for executing stream tasks */ @@ -142,27 +141,15 @@ const char *h2_session_state_str(h2_session_state state); * The session will apply the configured parameter. * @param psession pointer receiving the created session on success or NULL * @param c the connection to work on + * @param r optional request when protocol was upgraded * @param cfg the module config to apply * @param workers the worker pool to use * @return the created session */ apr_status_t h2_session_create(h2_session **psession, - conn_rec *c, struct h2_ctx *ctx, + conn_rec *c, request_rec *r, server_rec *, struct h2_workers *workers); -/** - * Create a new h2_session for the given request. - * The session will apply the configured parameter. - * @param psession pointer receiving the created session on success or NULL - * @param r the request that was upgraded - * @param cfg the module config to apply - * @param workers the worker pool to use - * @return the created session - */ -apr_status_t h2_session_rcreate(h2_session **psession, - request_rec *r, struct h2_ctx *ctx, - struct h2_workers *workers); - void h2_session_event(h2_session *session, h2_session_event_t ev, int err, const char *msg); diff --git a/modules/http2/h2_stream.c b/modules/http2/h2_stream.c index 24ebc56023..3cef6bae05 100644 --- a/modules/http2/h2_stream.c +++ b/modules/http2/h2_stream.c @@ -365,9 +365,8 @@ void h2_stream_dispatch(h2_stream *stream, h2_stream_event_t ev) static void set_policy_for(h2_stream *stream, h2_request *r) { int enabled = h2_session_push_enabled(stream->session); - stream->push_policy = h2_push_policy_determine(r->headers, stream->pool, - enabled); - r->serialize = h2_config_geti(stream->session->config, H2_CONF_SER_HEADERS); + stream->push_policy = h2_push_policy_determine(r->headers, stream->pool, enabled); + r->serialize = h2_config_sgeti(stream->session->s, H2_CONF_SER_HEADERS); } apr_status_t h2_stream_send_frame(h2_stream *stream, int ftype, int flags, size_t frame_len) @@ -987,7 +986,7 @@ const h2_priority *h2_stream_get_priority(h2_stream *stream, const char *ctype = apr_table_get(response->headers, "content-type"); if (ctype) { /* FIXME: Not good enough, config needs to come from request->server */ - return h2_config_get_priority(stream->session->config, ctype); + return h2_cconfig_get_priority(stream->session->c, ctype); } } return NULL; diff --git a/modules/http2/h2_switch.c b/modules/http2/h2_switch.c index 5e73568eeb..07a30cc690 100644 --- a/modules/http2/h2_switch.c +++ b/modules/http2/h2_switch.c @@ -55,7 +55,6 @@ static int h2_protocol_propose(conn_rec *c, request_rec *r, int is_tls = h2_h2_is_tls(c); const char **protos = is_tls? h2_tls_protos : h2_clear_protos; - (void)s; if (!h2_mpm_supported()) { return DECLINED; } @@ -68,7 +67,7 @@ static int h2_protocol_propose(conn_rec *c, request_rec *r, return DECLINED; } - if (!h2_is_acceptable_connection(c, 0)) { + if (!h2_is_acceptable_connection(c, r, 0)) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(03084) "protocol propose: connection requirements not met"); return DECLINED; @@ -81,7 +80,7 @@ static int h2_protocol_propose(conn_rec *c, request_rec *r, */ const char *p; - if (!h2_allows_h2_upgrade(c)) { + if (!h2_allows_h2_upgrade(r)) { return DECLINED; } @@ -150,7 +149,7 @@ static int h2_protocol_switch(conn_rec *c, request_rec *r, server_rec *s, ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "switching protocol to '%s'", protocol); h2_ctx_protocol_set(ctx, protocol); - h2_ctx_server_set(ctx, s); + h2_ctx_server_update(ctx, s); if (r != NULL) { apr_status_t status; @@ -164,8 +163,8 @@ static int h2_protocol_switch(conn_rec *c, request_rec *r, server_rec *s, ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER"); /* Ok, start an h2_conn on this one. */ - h2_ctx_server_set(ctx, r->server); - status = h2_conn_setup(ctx, r->connection, r); + status = h2_conn_setup(c, r, s); + if (status != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(03088) "session setup"); @@ -173,7 +172,7 @@ static int h2_protocol_switch(conn_rec *c, request_rec *r, server_rec *s, return !OK; } - h2_conn_run(ctx, c); + h2_conn_run(c); } return OK; } diff --git a/modules/http2/h2_task.c b/modules/http2/h2_task.c index 9a210b55c4..b67f7a1c34 100644 --- a/modules/http2/h2_task.c +++ b/modules/http2/h2_task.c @@ -236,7 +236,7 @@ static apr_status_t h2_filter_slave_in(ap_filter_t* f, apr_size_t rmax = ((readbytes <= APR_SIZE_MAX)? (apr_size_t)readbytes : APR_SIZE_MAX); - task = h2_ctx_cget_task(f->c); + task = h2_ctx_get_task(f->c); ap_assert(task); if (trace1) { @@ -379,7 +379,7 @@ static apr_status_t h2_filter_slave_in(ap_filter_t* f, static apr_status_t h2_filter_slave_output(ap_filter_t* filter, apr_bucket_brigade* brigade) { - h2_task *task = h2_ctx_cget_task(filter->c); + h2_task *task = h2_ctx_get_task(filter->c); apr_status_t status; ap_assert(task); @@ -392,7 +392,7 @@ static apr_status_t h2_filter_slave_output(ap_filter_t* filter, static apr_status_t h2_filter_parse_h1(ap_filter_t* f, apr_bucket_brigade* bb) { - h2_task *task = h2_ctx_cget_task(f->c); + h2_task *task = h2_ctx_get_task(f->c); apr_status_t status; ap_assert(task); @@ -502,7 +502,7 @@ static int h2_task_pre_conn(conn_rec* c, void *arg) ctx = h2_ctx_get(c, 0); (void)arg; - if (h2_ctx_is_task(ctx)) { + if (ctx->task) { ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_slave(%s), pre_connection, adding filters", c->log_id); ap_add_input_filter("H2_SLAVE_IN", NULL, NULL, c); @@ -545,6 +545,7 @@ h2_task *h2_task_create(conn_rec *slave, int stream_id, void h2_task_destroy(h2_task *task) { if (task->output.beam) { + h2_beam_log(task->output.beam, task->c, APLOG_TRACE2, "task_destroy"); h2_beam_destroy(task->output.beam); task->output.beam = NULL; } @@ -724,7 +725,7 @@ static int h2_task_process_conn(conn_rec* c) } ctx = h2_ctx_get(c, 0); - if (h2_ctx_is_task(ctx)) { + if (ctx->task) { if (!ctx->task->request->serialize) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, processing request directly"); diff --git a/modules/http2/h2_task.h b/modules/http2/h2_task.h index 52fe3fb96a..2624b11118 100644 --- a/modules/http2/h2_task.h +++ b/modules/http2/h2_task.h @@ -83,7 +83,9 @@ struct h2_task { unsigned int frozen : 1; unsigned int thawed : 1; unsigned int worker_started : 1; /* h2_worker started processing */ - unsigned int worker_done : 1; /* h2_worker finished */ + + int worker_done; /* h2_worker finished */ + int done_done; /* task_done has been handled */ apr_time_t started_at; /* when processing started */ apr_time_t done_at; /* when processing was done */ diff --git a/modules/http2/h2_version.h b/modules/http2/h2_version.h index 4ddfc9dd91..02d220a0bf 100644 --- a/modules/http2/h2_version.h +++ b/modules/http2/h2_version.h @@ -27,7 +27,7 @@ * @macro * Version number of the http2 module as c string */ -#define MOD_HTTP2_VERSION "1.12.0-DEV" +#define MOD_HTTP2_VERSION "1.12.2-DEV" /** * @macro @@ -35,7 +35,7 @@ * release. This is a 24 bit number with 8 bits for major number, 8 bits * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. */ -#define MOD_HTTP2_VERSION_NUM 0x010c00 +#define MOD_HTTP2_VERSION_NUM 0x010c02 #endif /* mod_h2_h2_version_h */ diff --git a/modules/http2/mod_http2.c b/modules/http2/mod_http2.c index 34c6a10e8c..1bcccd28c4 100644 --- a/modules/http2/mod_http2.c +++ b/modules/http2/mod_http2.c @@ -260,9 +260,8 @@ static const char *val_H2_PUSH(apr_pool_t *p, server_rec *s, { if (ctx) { if (r) { - h2_task *task = h2_ctx_get_task(ctx); - if (task) { - h2_stream *stream = h2_mplx_stream_get(task->mplx, task->stream_id); + if (ctx->task) { + h2_stream *stream = h2_mplx_stream_get(ctx->task->mplx, ctx->task->stream_id); if (stream && stream->push_policy != H2_PUSH_NONE) { return "on"; } @@ -273,8 +272,7 @@ static const char *val_H2_PUSH(apr_pool_t *p, server_rec *s, } } else if (s) { - const h2_config *cfg = h2_config_sget(s); - if (cfg && h2_config_geti(cfg, H2_CONF_PUSH)) { + if (h2_config_geti(r, s, H2_CONF_PUSH)) { return "on"; } } @@ -285,8 +283,7 @@ static const char *val_H2_PUSHED(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, h2_ctx *ctx) { if (ctx) { - h2_task *task = h2_ctx_get_task(ctx); - if (task && !H2_STREAM_CLIENT_INITIATED(task->stream_id)) { + if (ctx->task && !H2_STREAM_CLIENT_INITIATED(ctx->task->stream_id)) { return "PUSHED"; } } @@ -297,9 +294,8 @@ static const char *val_H2_PUSHED_ON(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, h2_ctx *ctx) { if (ctx) { - h2_task *task = h2_ctx_get_task(ctx); - if (task && !H2_STREAM_CLIENT_INITIATED(task->stream_id)) { - h2_stream *stream = h2_mplx_stream_get(task->mplx, task->stream_id); + if (ctx->task && !H2_STREAM_CLIENT_INITIATED(ctx->task->stream_id)) { + h2_stream *stream = h2_mplx_stream_get(ctx->task->mplx, ctx->task->stream_id); if (stream) { return apr_itoa(p, stream->initiated_on); } @@ -312,9 +308,8 @@ static const char *val_H2_STREAM_TAG(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, h2_ctx *ctx) { if (ctx) { - h2_task *task = h2_ctx_get_task(ctx); - if (task) { - return task->id; + if (ctx->task) { + return ctx->task->id; } } return ""; @@ -366,7 +361,7 @@ static char *http2_var_lookup(apr_pool_t *p, server_rec *s, for (i = 0; i < H2_ALEN(H2_VARS); ++i) { h2_var_def *vdef = &H2_VARS[i]; if (!strcmp(vdef->name, name)) { - h2_ctx *ctx = (r? h2_ctx_rget(r) : + h2_ctx *ctx = (r? h2_ctx_get(c, 0) : h2_ctx_get(c->master? c->master : c, 0)); return (char *)vdef->lookup(p, s, c, r, ctx); } @@ -377,7 +372,7 @@ static char *http2_var_lookup(apr_pool_t *p, server_rec *s, static int h2_h2_fixups(request_rec *r) { if (r->connection->master) { - h2_ctx *ctx = h2_ctx_rget(r); + h2_ctx *ctx = h2_ctx_get(r->connection, 0); int i; for (i = 0; ctx && i < H2_ALEN(H2_VARS); ++i) { diff --git a/modules/http2/mod_proxy_http2.c b/modules/http2/mod_proxy_http2.c index 21f8e1d1f9..4ac9325118 100644 --- a/modules/http2/mod_proxy_http2.c +++ b/modules/http2/mod_proxy_http2.c @@ -583,6 +583,14 @@ run_connect: */ apr_table_setn(ctx->p_conn->connection->notes, "proxy-request-alpn-protos", "h2"); + if (ctx->p_conn->ssl_hostname) { + ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, ctx->owner, + "set SNI to %s for (%s)", + ctx->p_conn->ssl_hostname, + ctx->p_conn->hostname); + apr_table_setn(ctx->p_conn->connection->notes, + "proxy-request-hostname", ctx->p_conn->ssl_hostname); + } } } |