Loading CHANGES +4 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,10 @@ Changes with Apache 2.4.18 *) mod_http2: new directive 'H2PushPriority' to allow priority specifications on server pushed streams according to their content-type. [Stefan Eissing] *) mod_http2: fixes crash on connection abort for a busy connection. fixes crash on a request that did not produce any response. [Stefan Eissing] Loading docs/manual/mod/mod_http2.xml +138 −2 Original line number Diff line number Diff line Loading @@ -112,6 +112,7 @@ <context>server config</context> <context>virtual host</context> </contextlist> <compatibility>Available in version 2.4.18 and later.</compatibility> <usage> <p> Loading Loading @@ -166,11 +167,143 @@ <p> Last but not least, pushes happen only when the client signals its willingness to accept those. Most browsers do, some, like Safari 9, do not. do not. Also, pushes also only happen for resources from the same <em>authority</em> as the original response is for. </p> </usage> </directivesynopsis> <directivesynopsis> <name>H2PushPriority</name> <description>H2 Server Push Priority</description> <syntax>H2PushPriority mime-type [after|before|interleaved] [weight]</syntax> <default>H2PushPriority * After 16</default> <contextlist> <context>server config</context> <context>virtual host</context> </contextlist> <compatibility>Available in version 2.4.18 and later. For having an effect, a nghttp2 library version newer than 1.4.0 is necessary.</compatibility> <usage> <p> This directive defines the priority handling of pushed responses based on the content-type of the response. This is usually defined per server config, but may also appear in a virtual host. </p> <p> HTTP/2 server pushes are always related to a client request. Each such request/response pairs, or <em>streams</em> have a dependency and a weight, together defining the <em>priority</em> of a stream. </p> <p> When a stream <em>depends</em> on another, say X depends on Y, then Y gets all bandwidth before X gets any. Note that this does not men that Y will block X. If Y has no data to send, all bandwidth allocated to Y can be used by X. </p> <p> When a stream has more than one dependant, say X1 and X2 both depend on Y, the <em>weight</em> determines the bandwidth allocation. If X1 and X2 have the same weight, they both get half of the available bandwdith. If the weight of X1 is twice as large as that for X2, X1 gets twice the bandwidth of X2. </p> <p> Ultimately, every stream depends on the <em>root</em> stream which gets all the bandwidht available, but never sends anything. So all its bandwidth is distributed by weight among its children. Which either have data to send or distribute the bandwidth to their own children. And so on. If none of the children have data to send, that bandwidth get distributed somewhere else according to the same rules. </p> <p> The purpose of this priority system is to always make use of available bandwidth while allowing precedence and weight to be given to specific streams. Since, normally, all streams are initiated by the client, it is also the one that sets these priorities. </p> <p> Only when such a stream results in a PUSH, gets the server to decide what the <em>initial</em> priority of such a pushed stream is. In the examples below, X is the client stream. It depends on Y and the server decides to PUSH streams P1 and P2 onto X. </p> <p> The default priority rule is: </p> <example><title>Default Priority Rule</title> <highlight language="config"> H2PushPriority * After 16 </highlight> </example> <p> which reads as 'Send a pushed stream of any content-type depending on the client stream with weight 16'. And so P1 and P2 will be send after X and, as they have equal weight, share bandwidth equally among themselves. </p> <example><title>Interleaved Priority Rule</title> <highlight language="config"> H2PushPriority text/css Interleaved 256 </highlight> </example> <p> which reads as 'Send any CSS resource on the same dependency and weight as the client stream'. If P1 has content-type 'text/css', it will depend on Y (as does X) and its effective weight will be calculated as <code>P1ew = Xw * (P1w / 256)</code>. With P1w being 256, this will make the effective weight the same as the weight of X. If both X and P1 have data to send, bandwidth will be allocated to both equally. </p> <p> With Pw specified as 512, a pushed, interleaved stream would get double the weight of X. With 128 only half as much. Note that effective weights are always capped at 256. </p> <example><title>Before Priority Rule</title> <highlight language="config"> H2PushPriority application/json Before 256 </highlight> </example> <p> This says that any pushed stream of content type 'application/json' should be send out <em>before</em> X. This makes P1 dependant on Y and X dependant on P1. So, X will be stalled as long as P1 has data to send. The effective weight is calculated as in the interleaved case. </p> <p> Be aware that the effect of priority specifications is limited by the available server resources. If a server does not have workers available for pushed streams, the data for the stream may only ever arrive when other streams have been finished. </p> <p> Last, but not least, there are some specifics of the syntax to be used in this directive. <ol> <li>'*' is the only special content-type that matches all oither. 'image/*' will not work.</li> <li>The default dependency is 'After'. </li> <li>There are also default weights: for 'After' it is 16, otherwise 256. </li> </ol> </p> <example><title>Shorter Priority Rules</title> <highlight language="config"> H2PushPriority application/json 32 # an After rule H2PushPriority image/jpeg before # weight 256 default H2PushPriority text/css interleaved # weight 256 default </highlight> </example> </usage> </directivesynopsis> <directivesynopsis> <name>H2Upgrade</name> <description>H2 Upgrade Protocol Switch</description> Loading Loading @@ -435,6 +568,7 @@ <context>server config</context> <context>virtual host</context> </contextlist> <compatibility>Available in version 2.4.18 and later.</compatibility> <usage> <p> Loading Loading @@ -482,6 +616,7 @@ <context>server config</context> <context>virtual host</context> </contextlist> <compatibility>Available in version 2.4.18 and later.</compatibility> <usage> <p> Loading Loading @@ -535,6 +670,7 @@ <context>server config</context> <context>virtual host</context> </contextlist> <compatibility>Available in version 2.4.18 and later.</compatibility> <usage> <p> Loading modules/http2/h2_alt_svc.c +1 −1 Original line number Diff line number Diff line Loading @@ -74,7 +74,7 @@ h2_alt_svc *h2_alt_svc_parse(const char *s, apr_pool_t *pool) { static int h2_alt_svc_handler(request_rec *r) { h2_ctx *ctx; h2_config *cfg; const h2_config *cfg; int i; if (r->connection->keepalives > 0) { Loading modules/http2/h2_config.c +99 −22 Original line number Diff line number Diff line Loading @@ -15,6 +15,9 @@ #include <assert.h> #include <apr_hash.h> #include <apr_lib.h> #include <httpd.h> #include <http_core.h> #include <http_config.h> Loading Loading @@ -43,7 +46,7 @@ static h2_config defconf = { H2_INITIAL_WINDOW_SIZE, /* window_size */ -1, /* min workers */ -1, /* max workers */ 10, /* max workers idle secs */ 10 * 60, /* max workers idle secs */ 64 * 1024, /* stream max mem size */ NULL, /* no alt-svcs */ -1, /* alt-svc max age */ Loading @@ -55,6 +58,7 @@ static h2_config defconf = { 1024*1024, /* TLS warmup size */ 1, /* TLS cooldown secs */ 1, /* HTTP/2 server push enabled */ NULL, /* map of content-type to priorities */ }; static int files_per_session = 0; Loading Loading @@ -111,6 +115,7 @@ static void *h2_config_create(apr_pool_t *pool, conf->tls_warmup_size = DEF_VAL; conf->tls_cooldown_secs = DEF_VAL; conf->h2_push = DEF_VAL; conf->priorities = NULL; return conf; } Loading Loading @@ -155,16 +160,22 @@ void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv) n->tls_warmup_size = H2_CONFIG_GET(add, base, tls_warmup_size); n->tls_cooldown_secs = H2_CONFIG_GET(add, base, tls_cooldown_secs); n->h2_push = H2_CONFIG_GET(add, base, h2_push); if (add->priorities && base->priorities) { n->priorities = apr_hash_overlay(pool, add->priorities, base->priorities); } else { n->priorities = add->priorities? add->priorities : base->priorities; } return n; } int h2_config_geti(h2_config *conf, h2_config_var_t var) int h2_config_geti(const h2_config *conf, h2_config_var_t var) { return (int)h2_config_geti64(conf, var); } apr_int64_t h2_config_geti64(h2_config *conf, h2_config_var_t var) apr_int64_t h2_config_geti64(const h2_config *conf, h2_config_var_t var) { int n; switch(var) { Loading Loading @@ -207,7 +218,7 @@ apr_int64_t h2_config_geti64(h2_config *conf, h2_config_var_t var) } } h2_config *h2_config_sget(server_rec *s) const h2_config *h2_config_sget(server_rec *s) { h2_config *cfg = (h2_config *)ap_get_module_config(s->module_config, &http2_module); Loading @@ -215,11 +226,21 @@ 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) { if (content_type && conf->priorities) { size_t len = strcspn(content_type, "; \t"); h2_priority *prio = apr_hash_get(conf->priorities, content_type, len); return prio? prio : apr_hash_get(conf->priorities, "*", 1); } return NULL; } static const char *h2_conf_set_max_streams(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); 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) { Loading @@ -231,7 +252,7 @@ static const char *h2_conf_set_max_streams(cmd_parms *parms, static const char *h2_conf_set_window_size(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); 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) { Loading @@ -243,7 +264,7 @@ static const char *h2_conf_set_window_size(cmd_parms *parms, static const char *h2_conf_set_min_workers(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); cfg->min_workers = (int)apr_atoi64(value); (void)arg; if (cfg->min_workers < 1) { Loading @@ -255,7 +276,7 @@ static const char *h2_conf_set_min_workers(cmd_parms *parms, static const char *h2_conf_set_max_workers(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); cfg->max_workers = (int)apr_atoi64(value); (void)arg; if (cfg->max_workers < 1) { Loading @@ -267,7 +288,7 @@ static const char *h2_conf_set_max_workers(cmd_parms *parms, static const char *h2_conf_set_max_worker_idle_secs(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); 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) { Loading @@ -279,7 +300,7 @@ static const char *h2_conf_set_max_worker_idle_secs(cmd_parms *parms, static const char *h2_conf_set_stream_max_mem_size(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); cfg->stream_max_mem_size = (int)apr_atoi64(value); Loading @@ -294,7 +315,7 @@ static const char *h2_add_alt_svc(cmd_parms *parms, void *arg, const char *value) { if (value && strlen(value)) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); h2_alt_svc *as = h2_alt_svc_parse(value, parms->pool); if (!as) { return "unable to parse alt-svc specifier"; Loading @@ -311,7 +332,7 @@ static const char *h2_add_alt_svc(cmd_parms *parms, static const char *h2_conf_set_alt_svc_max_age(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); cfg->alt_svc_max_age = (int)apr_atoi64(value); (void)arg; return NULL; Loading @@ -320,7 +341,7 @@ static const char *h2_conf_set_alt_svc_max_age(cmd_parms *parms, static const char *h2_conf_set_session_extra_files(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); apr_int64_t max = (int)apr_atoi64(value); if (max < 0) { return "value must be a non-negative number"; Loading @@ -333,7 +354,7 @@ static const char *h2_conf_set_session_extra_files(cmd_parms *parms, static const char *h2_conf_set_serialize_headers(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); if (!strcasecmp(value, "On")) { cfg->serialize_headers = 1; return NULL; Loading @@ -350,7 +371,7 @@ static const char *h2_conf_set_serialize_headers(cmd_parms *parms, static const char *h2_conf_set_direct(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); if (!strcasecmp(value, "On")) { cfg->h2_direct = 1; return NULL; Loading @@ -367,7 +388,7 @@ static const char *h2_conf_set_direct(cmd_parms *parms, static const char *h2_conf_set_push(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); if (!strcasecmp(value, "On")) { cfg->h2_push = 1; return NULL; Loading @@ -381,10 +402,64 @@ static const char *h2_conf_set_push(cmd_parms *parms, return "value must be On or Off"; } static const char *h2_conf_add_push_priority(cmd_parms *cmd, void *_cfg, const char *ctype, const char *sdependency, const char *sweight) { h2_config *cfg = (h2_config *)h2_config_sget(cmd->server); const char *sdefweight = "16"; /* default AFTER weight */ h2_dependency dependency; h2_priority *priority; int weight; if (!strlen(ctype)) { return "1st argument must be a mime-type, like 'text/css' or '*'"; } if (!sweight) { /* 2 args only, but which one? */ if (apr_isdigit(sdependency[0])) { sweight = sdependency; sdependency = "AFTER"; /* default dependency */ } } if (!strcasecmp("AFTER", sdependency)) { dependency = H2_DEPENDANT_AFTER; } else if (!strcasecmp("BEFORE", sdependency)) { dependency = H2_DEPENDANT_BEFORE; sdefweight = "256"; /* default BEFORE weight */ } else if (!strcasecmp("INTERLEAVED", sdependency)) { dependency = H2_DEPENDANT_INTERLEAVED; sdefweight = "256"; /* default INTERLEAVED weight */ } else { return "dependency must be one of 'After', 'Before' or 'Interleaved'"; } weight = (int)apr_atoi64(sweight? sweight : sdefweight); if (weight < NGHTTP2_MIN_WEIGHT) { return apr_psprintf(cmd->pool, "weight must be a number >= %d", NGHTTP2_MIN_WEIGHT); } priority = apr_pcalloc(cmd->pool, sizeof(*priority)); priority->dependency = dependency; priority->weight = weight; if (!cfg->priorities) { cfg->priorities = apr_hash_make(cmd->pool); } apr_hash_set(cfg->priorities, ctype, strlen(ctype), priority); return NULL; } static const char *h2_conf_set_modern_tls_only(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); if (!strcasecmp(value, "On")) { cfg->modern_tls_only = 1; return NULL; Loading @@ -401,7 +476,7 @@ static const char *h2_conf_set_modern_tls_only(cmd_parms *parms, static const char *h2_conf_set_upgrade(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); if (!strcasecmp(value, "On")) { cfg->h2_upgrade = 1; return NULL; Loading @@ -418,7 +493,7 @@ static const char *h2_conf_set_upgrade(cmd_parms *parms, static const char *h2_conf_set_tls_warmup_size(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); cfg->tls_warmup_size = apr_atoi64(value); (void)arg; return NULL; Loading @@ -427,7 +502,7 @@ static const char *h2_conf_set_tls_warmup_size(cmd_parms *parms, static const char *h2_conf_set_tls_cooldown_secs(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); cfg->tls_cooldown_secs = (int)apr_atoi64(value); (void)arg; return NULL; Loading Loading @@ -469,18 +544,20 @@ const command_rec h2_cmds[] = { 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"), AP_INIT_TAKE23("H2PushPriority", h2_conf_add_push_priority, NULL, RSRC_CONF, "define priority of PUSHed resources per content type"), AP_END_CMD }; h2_config *h2_config_rget(request_rec *r) 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); } h2_config *h2_config_get(conn_rec *c) const h2_config *h2_config_get(conn_rec *c) { h2_ctx *ctx = h2_ctx_get(c); Loading modules/http2/h2_config.h +13 −6 Original line number Diff line number Diff line Loading @@ -41,6 +41,9 @@ typedef enum { H2_CONF_PUSH, } h2_config_var_t; struct apr_hash_t; struct h2_priority; /* Apache httpd module configuration for h2. */ typedef struct h2_config { const char *name; Loading @@ -61,6 +64,7 @@ typedef struct h2_config { 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 */ } h2_config; Loading @@ -68,18 +72,21 @@ void *h2_config_create_dir(apr_pool_t *pool, char *x); void *h2_config_create_svr(apr_pool_t *pool, server_rec *s); void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv); apr_status_t h2_config_apply_header(h2_config *config, request_rec *r); apr_status_t h2_config_apply_header(const h2_config *config, request_rec *r); extern const command_rec h2_cmds[]; h2_config *h2_config_get(conn_rec *c); h2_config *h2_config_sget(server_rec *s); h2_config *h2_config_rget(request_rec *r); 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(h2_config *conf, h2_config_var_t var); apr_int64_t h2_config_geti64(h2_config *conf, 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); void h2_config_init(apr_pool_t *pool); const struct h2_priority *h2_config_get_priority(const h2_config *conf, const char *content_type); #endif /* __mod_h2__h2_config_h__ */ Loading
CHANGES +4 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,10 @@ Changes with Apache 2.4.18 *) mod_http2: new directive 'H2PushPriority' to allow priority specifications on server pushed streams according to their content-type. [Stefan Eissing] *) mod_http2: fixes crash on connection abort for a busy connection. fixes crash on a request that did not produce any response. [Stefan Eissing] Loading
docs/manual/mod/mod_http2.xml +138 −2 Original line number Diff line number Diff line Loading @@ -112,6 +112,7 @@ <context>server config</context> <context>virtual host</context> </contextlist> <compatibility>Available in version 2.4.18 and later.</compatibility> <usage> <p> Loading Loading @@ -166,11 +167,143 @@ <p> Last but not least, pushes happen only when the client signals its willingness to accept those. Most browsers do, some, like Safari 9, do not. do not. Also, pushes also only happen for resources from the same <em>authority</em> as the original response is for. </p> </usage> </directivesynopsis> <directivesynopsis> <name>H2PushPriority</name> <description>H2 Server Push Priority</description> <syntax>H2PushPriority mime-type [after|before|interleaved] [weight]</syntax> <default>H2PushPriority * After 16</default> <contextlist> <context>server config</context> <context>virtual host</context> </contextlist> <compatibility>Available in version 2.4.18 and later. For having an effect, a nghttp2 library version newer than 1.4.0 is necessary.</compatibility> <usage> <p> This directive defines the priority handling of pushed responses based on the content-type of the response. This is usually defined per server config, but may also appear in a virtual host. </p> <p> HTTP/2 server pushes are always related to a client request. Each such request/response pairs, or <em>streams</em> have a dependency and a weight, together defining the <em>priority</em> of a stream. </p> <p> When a stream <em>depends</em> on another, say X depends on Y, then Y gets all bandwidth before X gets any. Note that this does not men that Y will block X. If Y has no data to send, all bandwidth allocated to Y can be used by X. </p> <p> When a stream has more than one dependant, say X1 and X2 both depend on Y, the <em>weight</em> determines the bandwidth allocation. If X1 and X2 have the same weight, they both get half of the available bandwdith. If the weight of X1 is twice as large as that for X2, X1 gets twice the bandwidth of X2. </p> <p> Ultimately, every stream depends on the <em>root</em> stream which gets all the bandwidht available, but never sends anything. So all its bandwidth is distributed by weight among its children. Which either have data to send or distribute the bandwidth to their own children. And so on. If none of the children have data to send, that bandwidth get distributed somewhere else according to the same rules. </p> <p> The purpose of this priority system is to always make use of available bandwidth while allowing precedence and weight to be given to specific streams. Since, normally, all streams are initiated by the client, it is also the one that sets these priorities. </p> <p> Only when such a stream results in a PUSH, gets the server to decide what the <em>initial</em> priority of such a pushed stream is. In the examples below, X is the client stream. It depends on Y and the server decides to PUSH streams P1 and P2 onto X. </p> <p> The default priority rule is: </p> <example><title>Default Priority Rule</title> <highlight language="config"> H2PushPriority * After 16 </highlight> </example> <p> which reads as 'Send a pushed stream of any content-type depending on the client stream with weight 16'. And so P1 and P2 will be send after X and, as they have equal weight, share bandwidth equally among themselves. </p> <example><title>Interleaved Priority Rule</title> <highlight language="config"> H2PushPriority text/css Interleaved 256 </highlight> </example> <p> which reads as 'Send any CSS resource on the same dependency and weight as the client stream'. If P1 has content-type 'text/css', it will depend on Y (as does X) and its effective weight will be calculated as <code>P1ew = Xw * (P1w / 256)</code>. With P1w being 256, this will make the effective weight the same as the weight of X. If both X and P1 have data to send, bandwidth will be allocated to both equally. </p> <p> With Pw specified as 512, a pushed, interleaved stream would get double the weight of X. With 128 only half as much. Note that effective weights are always capped at 256. </p> <example><title>Before Priority Rule</title> <highlight language="config"> H2PushPriority application/json Before 256 </highlight> </example> <p> This says that any pushed stream of content type 'application/json' should be send out <em>before</em> X. This makes P1 dependant on Y and X dependant on P1. So, X will be stalled as long as P1 has data to send. The effective weight is calculated as in the interleaved case. </p> <p> Be aware that the effect of priority specifications is limited by the available server resources. If a server does not have workers available for pushed streams, the data for the stream may only ever arrive when other streams have been finished. </p> <p> Last, but not least, there are some specifics of the syntax to be used in this directive. <ol> <li>'*' is the only special content-type that matches all oither. 'image/*' will not work.</li> <li>The default dependency is 'After'. </li> <li>There are also default weights: for 'After' it is 16, otherwise 256. </li> </ol> </p> <example><title>Shorter Priority Rules</title> <highlight language="config"> H2PushPriority application/json 32 # an After rule H2PushPriority image/jpeg before # weight 256 default H2PushPriority text/css interleaved # weight 256 default </highlight> </example> </usage> </directivesynopsis> <directivesynopsis> <name>H2Upgrade</name> <description>H2 Upgrade Protocol Switch</description> Loading Loading @@ -435,6 +568,7 @@ <context>server config</context> <context>virtual host</context> </contextlist> <compatibility>Available in version 2.4.18 and later.</compatibility> <usage> <p> Loading Loading @@ -482,6 +616,7 @@ <context>server config</context> <context>virtual host</context> </contextlist> <compatibility>Available in version 2.4.18 and later.</compatibility> <usage> <p> Loading Loading @@ -535,6 +670,7 @@ <context>server config</context> <context>virtual host</context> </contextlist> <compatibility>Available in version 2.4.18 and later.</compatibility> <usage> <p> Loading
modules/http2/h2_alt_svc.c +1 −1 Original line number Diff line number Diff line Loading @@ -74,7 +74,7 @@ h2_alt_svc *h2_alt_svc_parse(const char *s, apr_pool_t *pool) { static int h2_alt_svc_handler(request_rec *r) { h2_ctx *ctx; h2_config *cfg; const h2_config *cfg; int i; if (r->connection->keepalives > 0) { Loading
modules/http2/h2_config.c +99 −22 Original line number Diff line number Diff line Loading @@ -15,6 +15,9 @@ #include <assert.h> #include <apr_hash.h> #include <apr_lib.h> #include <httpd.h> #include <http_core.h> #include <http_config.h> Loading Loading @@ -43,7 +46,7 @@ static h2_config defconf = { H2_INITIAL_WINDOW_SIZE, /* window_size */ -1, /* min workers */ -1, /* max workers */ 10, /* max workers idle secs */ 10 * 60, /* max workers idle secs */ 64 * 1024, /* stream max mem size */ NULL, /* no alt-svcs */ -1, /* alt-svc max age */ Loading @@ -55,6 +58,7 @@ static h2_config defconf = { 1024*1024, /* TLS warmup size */ 1, /* TLS cooldown secs */ 1, /* HTTP/2 server push enabled */ NULL, /* map of content-type to priorities */ }; static int files_per_session = 0; Loading Loading @@ -111,6 +115,7 @@ static void *h2_config_create(apr_pool_t *pool, conf->tls_warmup_size = DEF_VAL; conf->tls_cooldown_secs = DEF_VAL; conf->h2_push = DEF_VAL; conf->priorities = NULL; return conf; } Loading Loading @@ -155,16 +160,22 @@ void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv) n->tls_warmup_size = H2_CONFIG_GET(add, base, tls_warmup_size); n->tls_cooldown_secs = H2_CONFIG_GET(add, base, tls_cooldown_secs); n->h2_push = H2_CONFIG_GET(add, base, h2_push); if (add->priorities && base->priorities) { n->priorities = apr_hash_overlay(pool, add->priorities, base->priorities); } else { n->priorities = add->priorities? add->priorities : base->priorities; } return n; } int h2_config_geti(h2_config *conf, h2_config_var_t var) int h2_config_geti(const h2_config *conf, h2_config_var_t var) { return (int)h2_config_geti64(conf, var); } apr_int64_t h2_config_geti64(h2_config *conf, h2_config_var_t var) apr_int64_t h2_config_geti64(const h2_config *conf, h2_config_var_t var) { int n; switch(var) { Loading Loading @@ -207,7 +218,7 @@ apr_int64_t h2_config_geti64(h2_config *conf, h2_config_var_t var) } } h2_config *h2_config_sget(server_rec *s) const h2_config *h2_config_sget(server_rec *s) { h2_config *cfg = (h2_config *)ap_get_module_config(s->module_config, &http2_module); Loading @@ -215,11 +226,21 @@ 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) { if (content_type && conf->priorities) { size_t len = strcspn(content_type, "; \t"); h2_priority *prio = apr_hash_get(conf->priorities, content_type, len); return prio? prio : apr_hash_get(conf->priorities, "*", 1); } return NULL; } static const char *h2_conf_set_max_streams(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); 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) { Loading @@ -231,7 +252,7 @@ static const char *h2_conf_set_max_streams(cmd_parms *parms, static const char *h2_conf_set_window_size(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); 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) { Loading @@ -243,7 +264,7 @@ static const char *h2_conf_set_window_size(cmd_parms *parms, static const char *h2_conf_set_min_workers(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); cfg->min_workers = (int)apr_atoi64(value); (void)arg; if (cfg->min_workers < 1) { Loading @@ -255,7 +276,7 @@ static const char *h2_conf_set_min_workers(cmd_parms *parms, static const char *h2_conf_set_max_workers(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); cfg->max_workers = (int)apr_atoi64(value); (void)arg; if (cfg->max_workers < 1) { Loading @@ -267,7 +288,7 @@ static const char *h2_conf_set_max_workers(cmd_parms *parms, static const char *h2_conf_set_max_worker_idle_secs(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); 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) { Loading @@ -279,7 +300,7 @@ static const char *h2_conf_set_max_worker_idle_secs(cmd_parms *parms, static const char *h2_conf_set_stream_max_mem_size(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); cfg->stream_max_mem_size = (int)apr_atoi64(value); Loading @@ -294,7 +315,7 @@ static const char *h2_add_alt_svc(cmd_parms *parms, void *arg, const char *value) { if (value && strlen(value)) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); h2_alt_svc *as = h2_alt_svc_parse(value, parms->pool); if (!as) { return "unable to parse alt-svc specifier"; Loading @@ -311,7 +332,7 @@ static const char *h2_add_alt_svc(cmd_parms *parms, static const char *h2_conf_set_alt_svc_max_age(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); cfg->alt_svc_max_age = (int)apr_atoi64(value); (void)arg; return NULL; Loading @@ -320,7 +341,7 @@ static const char *h2_conf_set_alt_svc_max_age(cmd_parms *parms, static const char *h2_conf_set_session_extra_files(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); apr_int64_t max = (int)apr_atoi64(value); if (max < 0) { return "value must be a non-negative number"; Loading @@ -333,7 +354,7 @@ static const char *h2_conf_set_session_extra_files(cmd_parms *parms, static const char *h2_conf_set_serialize_headers(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); if (!strcasecmp(value, "On")) { cfg->serialize_headers = 1; return NULL; Loading @@ -350,7 +371,7 @@ static const char *h2_conf_set_serialize_headers(cmd_parms *parms, static const char *h2_conf_set_direct(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); if (!strcasecmp(value, "On")) { cfg->h2_direct = 1; return NULL; Loading @@ -367,7 +388,7 @@ static const char *h2_conf_set_direct(cmd_parms *parms, static const char *h2_conf_set_push(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); if (!strcasecmp(value, "On")) { cfg->h2_push = 1; return NULL; Loading @@ -381,10 +402,64 @@ static const char *h2_conf_set_push(cmd_parms *parms, return "value must be On or Off"; } static const char *h2_conf_add_push_priority(cmd_parms *cmd, void *_cfg, const char *ctype, const char *sdependency, const char *sweight) { h2_config *cfg = (h2_config *)h2_config_sget(cmd->server); const char *sdefweight = "16"; /* default AFTER weight */ h2_dependency dependency; h2_priority *priority; int weight; if (!strlen(ctype)) { return "1st argument must be a mime-type, like 'text/css' or '*'"; } if (!sweight) { /* 2 args only, but which one? */ if (apr_isdigit(sdependency[0])) { sweight = sdependency; sdependency = "AFTER"; /* default dependency */ } } if (!strcasecmp("AFTER", sdependency)) { dependency = H2_DEPENDANT_AFTER; } else if (!strcasecmp("BEFORE", sdependency)) { dependency = H2_DEPENDANT_BEFORE; sdefweight = "256"; /* default BEFORE weight */ } else if (!strcasecmp("INTERLEAVED", sdependency)) { dependency = H2_DEPENDANT_INTERLEAVED; sdefweight = "256"; /* default INTERLEAVED weight */ } else { return "dependency must be one of 'After', 'Before' or 'Interleaved'"; } weight = (int)apr_atoi64(sweight? sweight : sdefweight); if (weight < NGHTTP2_MIN_WEIGHT) { return apr_psprintf(cmd->pool, "weight must be a number >= %d", NGHTTP2_MIN_WEIGHT); } priority = apr_pcalloc(cmd->pool, sizeof(*priority)); priority->dependency = dependency; priority->weight = weight; if (!cfg->priorities) { cfg->priorities = apr_hash_make(cmd->pool); } apr_hash_set(cfg->priorities, ctype, strlen(ctype), priority); return NULL; } static const char *h2_conf_set_modern_tls_only(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); if (!strcasecmp(value, "On")) { cfg->modern_tls_only = 1; return NULL; Loading @@ -401,7 +476,7 @@ static const char *h2_conf_set_modern_tls_only(cmd_parms *parms, static const char *h2_conf_set_upgrade(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); if (!strcasecmp(value, "On")) { cfg->h2_upgrade = 1; return NULL; Loading @@ -418,7 +493,7 @@ static const char *h2_conf_set_upgrade(cmd_parms *parms, static const char *h2_conf_set_tls_warmup_size(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); cfg->tls_warmup_size = apr_atoi64(value); (void)arg; return NULL; Loading @@ -427,7 +502,7 @@ static const char *h2_conf_set_tls_warmup_size(cmd_parms *parms, static const char *h2_conf_set_tls_cooldown_secs(cmd_parms *parms, void *arg, const char *value) { h2_config *cfg = h2_config_sget(parms->server); h2_config *cfg = (h2_config *)h2_config_sget(parms->server); cfg->tls_cooldown_secs = (int)apr_atoi64(value); (void)arg; return NULL; Loading Loading @@ -469,18 +544,20 @@ const command_rec h2_cmds[] = { 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"), AP_INIT_TAKE23("H2PushPriority", h2_conf_add_push_priority, NULL, RSRC_CONF, "define priority of PUSHed resources per content type"), AP_END_CMD }; h2_config *h2_config_rget(request_rec *r) 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); } h2_config *h2_config_get(conn_rec *c) const h2_config *h2_config_get(conn_rec *c) { h2_ctx *ctx = h2_ctx_get(c); Loading
modules/http2/h2_config.h +13 −6 Original line number Diff line number Diff line Loading @@ -41,6 +41,9 @@ typedef enum { H2_CONF_PUSH, } h2_config_var_t; struct apr_hash_t; struct h2_priority; /* Apache httpd module configuration for h2. */ typedef struct h2_config { const char *name; Loading @@ -61,6 +64,7 @@ typedef struct h2_config { 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 */ } h2_config; Loading @@ -68,18 +72,21 @@ void *h2_config_create_dir(apr_pool_t *pool, char *x); void *h2_config_create_svr(apr_pool_t *pool, server_rec *s); void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv); apr_status_t h2_config_apply_header(h2_config *config, request_rec *r); apr_status_t h2_config_apply_header(const h2_config *config, request_rec *r); extern const command_rec h2_cmds[]; h2_config *h2_config_get(conn_rec *c); h2_config *h2_config_sget(server_rec *s); h2_config *h2_config_rget(request_rec *r); 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(h2_config *conf, h2_config_var_t var); apr_int64_t h2_config_geti64(h2_config *conf, 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); void h2_config_init(apr_pool_t *pool); const struct h2_priority *h2_config_get_priority(const h2_config *conf, const char *content_type); #endif /* __mod_h2__h2_config_h__ */