]> granicus.if.org Git - apache/commitdiff
merged mod_http2 1.0.8 from trunk
authorStefan Eissing <icing@apache.org>
Wed, 25 Nov 2015 17:12:38 +0000 (17:12 +0000)
committerStefan Eissing <icing@apache.org>
Wed, 25 Nov 2015 17:12:38 +0000 (17:12 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1716493 13f79535-47bb-0310-9956-ffa450edef68

25 files changed:
CHANGES
docs/manual/mod/mod_http2.xml
modules/http2/h2_alt_svc.c
modules/http2/h2_config.c
modules/http2/h2_config.h
modules/http2/h2_conn.c
modules/http2/h2_conn.h
modules/http2/h2_conn_io.c
modules/http2/h2_conn_io.h
modules/http2/h2_ctx.h
modules/http2/h2_h2.c
modules/http2/h2_mplx.c
modules/http2/h2_mplx.h
modules/http2/h2_push.c
modules/http2/h2_push.h
modules/http2/h2_request.c
modules/http2/h2_request.h
modules/http2/h2_session.c
modules/http2/h2_session.h
modules/http2/h2_stream.c
modules/http2/h2_stream.h
modules/http2/h2_switch.c
modules/http2/h2_task.c
modules/http2/h2_task.h
modules/http2/h2_version.h

diff --git a/CHANGES b/CHANGES
index eb50dcbf3c394dadbecc84a9ef82c63cbf136b70..66b3be69ae6d68b19be9d60ae213d2c30c7cdb5e 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -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]
index 0771e3c44ee02d032c89396c4a2952e12edf851b..e06b1faebdbee647f1c2a3f8cd29b023034faa38 100644 (file)
             <context>server config</context>
             <context>virtual host</context>
         </contextlist>
+        <compatibility>Available in version 2.4.18 and later.</compatibility>
         
         <usage>
             <p>
             <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>
             <context>server config</context>
             <context>virtual host</context>
         </contextlist>
-        
+        <compatibility>Available in version 2.4.18 and later.</compatibility>
+
         <usage>
             <p>
                 This directive toggles the security checks on HTTP/2 connections
             <context>server config</context>
             <context>virtual host</context>
         </contextlist>
+        <compatibility>Available in version 2.4.18 and later.</compatibility>
         
         <usage>
             <p>
             <context>server config</context>
             <context>virtual host</context>
         </contextlist>
+        <compatibility>Available in version 2.4.18 and later.</compatibility>
         
         <usage>
             <p>
index d18ae5f20de42a9fc1287b7ae83a881d19c20a3c..6bc3cd0dff5358ec2425fe3fa4e54f91097f7271 100644 (file)
@@ -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) {
index 7dc0b20d20d34649f6f66cae12f2bda9fb467a03..11f9b0a609534a827f83516c04bab9fbbeae59ef 100644 (file)
@@ -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>
@@ -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 */
@@ -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;
@@ -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;
 }
@@ -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) {
@@ -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);
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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);
@@ -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";
@@ -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;
@@ -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";
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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);
     
index 7d2ed0fa28e1ee5c7479d731b3afe10d9ecdeae4..3d85ec247d3b9ef3aa7ab0eb4924b74699053cf2 100644 (file)
@@ -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;
@@ -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;
 
 
@@ -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__ */
 
index 6fec75ea9a08daa9819c862ac6e698b51da834a2..cf44fd7c1fcdf7e321eafb2cd09126416b9e329b 100644 (file)
@@ -69,7 +69,7 @@ static void check_modules(void)
 
 apr_status_t h2_conn_child_init(apr_pool_t *pool, server_rec *s)
 {
-    h2_config *config = h2_config_sget(s);
+    const h2_config *config = h2_config_sget(s);
     apr_status_t status = APR_SUCCESS;
     int minw = h2_config_geti(config, H2_CONF_MIN_WORKERS);
     int maxw = h2_config_geti(config, H2_CONF_MAX_WORKERS);
@@ -131,11 +131,11 @@ static module *h2_conn_mpm_module(void) {
     return mpm_module;
 }
 
-apr_status_t h2_conn_process(conn_rec *c, request_rec *r)
+apr_status_t h2_conn_process(conn_rec *c, request_rec *r, server_rec *s)
 {
     apr_status_t status;
     h2_session *session;
-    h2_config *config;
+    const h2_config *config;
     int rv;
     
     if (!workers) {
@@ -146,12 +146,15 @@ apr_status_t h2_conn_process(conn_rec *c, request_rec *r)
     
     ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "h2_conn_process start");
     
+    if (!s && r) {
+        s = r->server;
+    }
+    
+    config = s? h2_config_sget(s) : h2_config_get(c);
     if (r) {
-        config = h2_config_rget(r);
         session = h2_session_rcreate(r, config, workers);
     }
     else {
-        config = h2_config_get(c);
         session = h2_session_create(c, config, workers);
     }
     
index 84cf8d83c407e2f6164e9a68935500c0e972f5fc..917a57e0392af369625737f249b5636af2236cc2 100644 (file)
@@ -24,9 +24,10 @@ struct h2_task;
  * and the connection will close.
  *
  * @param c the connection HTTP/2 is starting on
- * @param r the upgrad requestion that still awaits an answer, optional
+ * @param r the upgrade request that still awaits an answer, optional
+ * @param s the server selected by request or, if NULL, connection
  */
-apr_status_t h2_conn_process(conn_rec *c, request_rec *r);
+apr_status_t h2_conn_process(conn_rec *c, request_rec *r, server_rec *s);
 
 /* Initialize this child process for h2 connection work,
  * to be called once during child init before multi processing
index 485a8bd47ea4e8f03ba947d5b042ad99ad3c1b98..a67d025fa883c299f3afd8ee08e583ff01de5847 100644 (file)
 
 #define WRITE_BUFFER_SIZE     (8*WRITE_SIZE_MAX)
 
-apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, apr_pool_t *pool)
+apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, 
+                             const h2_config *cfg, 
+                             apr_pool_t *pool)
 {
-    h2_config *cfg = h2_config_get(c);
-    
     io->connection         = c;
     io->input              = apr_brigade_create(pool, c->bucket_alloc);
     io->output             = apr_brigade_create(pool, c->bucket_alloc);
index a0dd0d0e5caf3ffaca6ad23ac3a73af336083bfd..f051c6c3d9adba22171ec9687731cf0b2e42db77 100644 (file)
@@ -16,6 +16,8 @@
 #ifndef __mod_h2__h2_conn_io__
 #define __mod_h2__h2_conn_io__
 
+struct h2_config;
+
 /* h2_io is the basic handler of a httpd connection. It keeps two brigades,
  * one for input, one for output and works with the installed connection
  * filters.
@@ -42,7 +44,9 @@ typedef struct {
     int unflushed;
 } h2_conn_io;
 
-apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, apr_pool_t *pool);
+apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, 
+                             const struct h2_config *cfg, 
+                             apr_pool_t *pool);
 
 int h2_conn_io_is_buffered(h2_conn_io *io);
 
index e4bc7506ae69ad025431078c7be026b47e2d7bfd..7f8f2b5949d262b8871cf06aadc550135da74ad8 100644 (file)
@@ -28,12 +28,12 @@ struct h2_config;
  * - those created by ourself to perform work on HTTP/2 streams
  */
 typedef struct h2_ctx {
-    int is_h2;                    /* h2 engine is used */
-    const char *protocol;         /* the protocol negotiated */
-    struct h2_task *task;         /* the h2_task executing or NULL */
-    const char *hostname;         /* hostname negotiated via SNI, optional */
-    server_rec *server;           /* httpd server config selected. */
-    struct h2_config *config;     /* effective config in this context */
+    int is_h2;                      /* h2 engine is used */
+    const char *protocol;           /* the protocol negotiated */
+    struct h2_task *task;           /* the h2_task executing or NULL */
+    const char *hostname;           /* hostname negotiated via SNI, optional */
+    server_rec *server;             /* httpd server config selected. */
+    const struct h2_config *config; /* effective config in this context */
 } h2_ctx;
 
 h2_ctx *h2_ctx_get(const conn_rec *c);
index e48e64e8a467f2d0acf709141f12a9309cc9ff73..3b62dbf1c8d220307acc5f7d7ebe6e92aee0c5c0 100644 (file)
@@ -469,7 +469,7 @@ int h2_h2_is_tls(conn_rec *c)
 int h2_is_acceptable_connection(conn_rec *c, int require_all) 
 {
     int is_tls = h2_h2_is_tls(c);
-    h2_config *cfg = h2_config_get(c);
+    const h2_config *cfg = h2_config_get(c);
 
     if (is_tls && h2_config_geti(cfg, H2_CONF_MODERN_TLS_ONLY) > 0) {
         /* Check TLS connection for modern TLS parameters, as defined in
@@ -526,7 +526,7 @@ int h2_is_acceptable_connection(conn_rec *c, int require_all)
 
 int h2_allows_h2_direct(conn_rec *c)
 {
-    h2_config *cfg = h2_config_get(c);
+    const h2_config *cfg = h2_config_get(c);
     int h2_direct = h2_config_geti(cfg, H2_CONF_DIRECT);
     
     if (h2_direct < 0) {
@@ -544,7 +544,7 @@ int h2_allows_h2_direct(conn_rec *c)
 
 int h2_allows_h2_upgrade(conn_rec *c)
 {
-    h2_config *cfg = h2_config_get(c);
+    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));
@@ -651,7 +651,7 @@ int h2_h2_process_conn(conn_rec* c)
         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
                       "h2_h2, connection, h2 active");
         
-        return h2_conn_process(c, NULL);
+        return h2_conn_process(c, NULL, ctx->server);
     }
     
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, declined");
index 6f2a512465146ed6d8d6be6cf864d2c3102a8ec3..c4efed6276d6ac66a31013881cc2a06a8417c757 100644 (file)
@@ -102,10 +102,11 @@ static void h2_mplx_destroy(h2_mplx *m)
  *   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, h2_workers *workers)
+h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *parent, 
+                        const h2_config *conf,
+                        h2_workers *workers)
 {
     apr_status_t status = APR_SUCCESS;
-    h2_config *conf = h2_config_get(c);
     apr_allocator_t *allocator = NULL;
     h2_mplx *m;
     AP_DEBUG_ASSERT(conf);
index c570e91fd43b96c72ed08ed3785eb1e7b7518e43..f145428ff3cc2b0117739f587e6fa58cb2768160 100644 (file)
@@ -88,6 +88,7 @@ struct h2_mplx {
  * Implicitly has reference count 1.
  */
 h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *master, 
+                        const struct h2_config *conf, 
                         struct h2_workers *workers);
 
 /**
index 65b2b7b625127cf9a10c46f980de0d9689d0541d..b80ffb90812aecb0fc41d99f776ecd19d3c9d401 100644 (file)
@@ -282,7 +282,6 @@ static int add_push(link_ctx *ctx)
                 path = apr_uri_unparse(ctx->pool, &uri, APR_URI_UNP_OMITSITEPART);
                 
                 push = apr_pcalloc(ctx->pool, sizeof(*push));
-                push->initiating_id = ctx->req->id;
                 
                 headers = apr_table_make(ctx->pool, 5);
                 apr_table_do(set_header, headers, ctx->req->headers,
@@ -290,20 +289,13 @@ static int add_push(link_ctx *ctx)
                              "Cache-Control",
                              "Accept-Language",
                              NULL);
-                /* TODO: which headers do we add here?
-                 */
-                
-                req = h2_request_createn(0, ctx->pool,
-                                         ctx->req->method, 
-                                         ctx->req->scheme,
+                req = h2_request_createn(0, ctx->pool, ctx->req->config, 
+                                         "GET", ctx->req->scheme,
                                          ctx->req->authority, 
                                          path, headers);
                 h2_request_end_headers(req, ctx->pool, 1);
                 push->req = req;
                 
-                push->prio.dependency = H2_DEPENDANT_AFTER;
-                push->prio.weight = NGHTTP2_DEFAULT_WEIGHT;
-                
                 if (!ctx->pushes) {
                     ctx->pushes = apr_array_make(ctx->pool, 5, sizeof(h2_push*));
                 }
index b98a2f73e17937c4a372e4c1ec8a6951fae818d5..871548cee3fa13733377a48d95e2fe584d9f1bcc 100644 (file)
@@ -20,9 +20,7 @@ struct h2_response;
 struct h2_ngheader;
 
 typedef struct h2_push {
-    int          initiating_id;
     const struct h2_request *req;
-    h2_priority  prio;
 } h2_push;
 
 
index e1a371f6a41ff67033255d81f1afdf44d6140828..bce58593c1557654cc47ddd463935c0e46a75c81 100644 (file)
 #include <scoreboard.h>
 
 #include "h2_private.h"
+#include "h2_config.h"
 #include "h2_mplx.h"
 #include "h2_request.h"
 #include "h2_task.h"
 #include "h2_util.h"
 
 
-h2_request *h2_request_create(int id, apr_pool_t *pool)
+h2_request *h2_request_create(int id, apr_pool_t *pool,
+                              const struct h2_config *config)
 {
-    return h2_request_createn(id, pool, NULL, NULL, NULL, NULL, NULL);
+    return h2_request_createn(id, pool, config, 
+                              NULL, NULL, NULL, NULL, NULL);
 }
 
 h2_request *h2_request_createn(int id, apr_pool_t *pool,
+                               const struct h2_config *config, 
                                const char *method, const char *scheme,
                                const char *authority, const char *path,
                                apr_table_t *header)
@@ -49,6 +53,7 @@ h2_request *h2_request_createn(int id, apr_pool_t *pool,
     h2_request *req = apr_pcalloc(pool, sizeof(h2_request));
     
     req->id             = id;
+    req->config         = config;
     req->method         = method;
     req->scheme         = scheme;
     req->authority      = authority;
@@ -137,6 +142,7 @@ apr_status_t h2_request_rwrite(h2_request *req, request_rec *r)
 {
     apr_status_t status;
     
+    req->config    = h2_config_rget(r);
     req->method    = r->method;
     req->scheme    = (r->parsed_uri.scheme? r->parsed_uri.scheme
                       : ap_http_scheme(r));
index 69d24f38a2eb73acfaddbce385053b221150227d..9e74492cd9de6e4d34cbb7b59204b1cdf1c7f996 100644 (file)
@@ -20,6 +20,7 @@
  * format that will be fed to various httpd input filters to finally
  * become a request_rec to be handled by soemone.
  */
+struct h2_config;
 struct h2_to_h1;
 struct h2_mplx;
 struct h2_task;
@@ -42,11 +43,15 @@ struct h2_request {
     apr_off_t content_length;
     int chunked;
     int eoh;
+    
+    const struct h2_config *config;
 };
 
-h2_request *h2_request_create(int id, apr_pool_t *pool);
+h2_request *h2_request_create(int id, apr_pool_t *pool, 
+                              const struct h2_config *config);
 
 h2_request *h2_request_createn(int id, apr_pool_t *pool,
+                               const struct h2_config *config, 
                                const char *method, const char *scheme,
                                const char *authority, const char *path,
                                apr_table_t *headers);
index 91a3d9465cdc02f5f24a5860d84906b56fce82f6..ca1d87824de8ac3074d1fa17a69ab51c89670e22 100644 (file)
@@ -550,6 +550,22 @@ static int on_send_data_cb(nghttp2_session *ngh2,
     return h2_session_status_from_apr_status(status);
 }
 
+static int on_frame_send_cb(nghttp2_session *ngh2, 
+                            const nghttp2_frame *frame,
+                            void *user_data)
+{
+    h2_session *session = user_data;
+    if (APLOGctrace1(session->c)) {
+        char buffer[256];
+        
+        frame_print(frame, buffer, sizeof(buffer)/sizeof(buffer[0]));
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c,
+                      "h2_session(%ld): frame_send %s",
+                      session->id, buffer);
+    }
+    return 0;
+}
+
 #define NGH2_SET_CALLBACK(callbacks, name, fn)\
 nghttp2_session_callbacks_set_##name##_callback(callbacks, fn)
 
@@ -571,7 +587,8 @@ static apr_status_t init_callbacks(conn_rec *c, nghttp2_session_callbacks **pcb)
     NGH2_SET_CALLBACK(*pcb, on_begin_headers, on_begin_headers_cb);
     NGH2_SET_CALLBACK(*pcb, on_header, on_header_cb);
     NGH2_SET_CALLBACK(*pcb, send_data, on_send_data_cb);
-    
+    NGH2_SET_CALLBACK(*pcb, on_frame_send, on_frame_send_cb);
+
     return APR_SUCCESS;
 }
 
@@ -625,7 +642,7 @@ static void *session_realloc(void *p, size_t size, void *ctx)
 
 static h2_session *h2_session_create_int(conn_rec *c,
                                          request_rec *r,
-                                         h2_config *config, 
+                                         const h2_config *config, 
                                          h2_workers *workers)
 {
     nghttp2_session_callbacks *callbacks = NULL;
@@ -646,6 +663,7 @@ static h2_session *h2_session_create_int(conn_rec *c,
         session->id = c->id;
         session->c = c;
         session->r = r;
+        session->config = config;
         
         session->pool = pool;
         apr_pool_pre_cleanup_register(pool, session, session_pool_cleanup);
@@ -661,9 +679,9 @@ static h2_session *h2_session_create_int(conn_rec *c,
         session->streams = h2_stream_set_create(session->pool, session->max_stream_count);
         
         session->workers = workers;
-        session->mplx = h2_mplx_create(c, session->pool, workers);
+        session->mplx = h2_mplx_create(c, session->pool, config, workers);
         
-        h2_conn_io_init(&session->io, c, session->pool);
+        h2_conn_io_init(&session->io, c, config, session->pool);
         session->bbtmp = apr_brigade_create(session->pool, c->bucket_alloc);
         
         status = init_callbacks(c, &callbacks);
@@ -718,13 +736,13 @@ static h2_session *h2_session_create_int(conn_rec *c,
     return session;
 }
 
-h2_session *h2_session_create(conn_rec *c, h2_config *config, 
+h2_session *h2_session_create(conn_rec *c, const h2_config *config, 
                               h2_workers *workers)
 {
     return h2_session_create_int(c, NULL, config, workers);
 }
 
-h2_session *h2_session_rcreate(request_rec *r, h2_config *config, 
+h2_session *h2_session_rcreate(request_rec *r, const h2_config *config, 
                                h2_workers *workers)
 {
     return h2_session_create_int(r->connection, r, config, workers);
@@ -851,7 +869,6 @@ apr_status_t h2_session_abort(h2_session *session, apr_status_t reason, int rv)
 apr_status_t h2_session_start(h2_session *session, int *rv)
 {
     apr_status_t status = APR_SUCCESS;
-    h2_config *config;
     nghttp2_settings_entry settings[3];
     size_t slen;
     int i;
@@ -859,15 +876,11 @@ apr_status_t h2_session_start(h2_session *session, int *rv)
     AP_DEBUG_ASSERT(session);
     /* Start the conversation by submitting our SETTINGS frame */
     *rv = 0;
-    config = h2_config_get(session->c);
     if (session->r) {
         const char *s, *cs;
         apr_size_t dlen; 
         h2_stream * stream;
 
-        /* better for vhost matching */
-        config = h2_config_rget(session->r);
-        
         /* 'h2c' mode: we should have a 'HTTP2-Settings' header with
          * base64 encoded client settings. */
         s = apr_table_get(session->r->headers_in, "HTTP2-Settings");
@@ -921,7 +934,7 @@ 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;
-    i = h2_config_geti(config, H2_CONF_WIN_SIZE);
+    i = h2_config_geti(session->config, H2_CONF_WIN_SIZE);
     if (i != H2_INITIAL_WINDOW_SIZE) {
         settings[slen].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
         settings[slen].value = i;
@@ -1167,7 +1180,7 @@ static apr_status_t submit_response(h2_session *session, h2_stream *stream)
         nghttp2_data_provider provider;
         h2_response *response = stream->response;
         h2_ngheader *ngh;
-        h2_priority *prio;
+        const h2_priority *prio;
         
         memset(&provider, 0, sizeof(provider));
         provider.source.fd = stream->id;
@@ -1203,7 +1216,7 @@ static apr_status_t submit_response(h2_session *session, h2_stream *stream)
          */
         if (!rv 
             && !stream->initiated_on
-            && h2_config_geti(h2_config_get(session->c), H2_CONF_PUSH)
+            && h2_config_geti(session->config, H2_CONF_PUSH)
             && H2_HTTP_2XX(response->http_status)
             && h2_session_push_enabled(session)) {
             
@@ -1243,26 +1256,24 @@ struct h2_stream *h2_session_push(h2_session *session, h2_stream *is,
     int nid;
     
     ngh = h2_util_ngheader_make_req(is->pool, push->req);
-    nid = nghttp2_submit_push_promise(session->ngh2, 0, push->initiating_id, 
+    nid = nghttp2_submit_push_promise(session->ngh2, 0, is->id, 
                                       ngh->nv, ngh->nvlen, NULL);
                                       
     if (nid <= 0) {
         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
                       "h2_stream(%ld-%d): submitting push promise fail: %s",
-                      session->id, push->initiating_id, 
-                      nghttp2_strerror(nid));
+                      session->id, is->id, nghttp2_strerror(nid));
         return NULL;
     }
     
     ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
-                  "h2_stream(%ld-%d): promised new stream %d for %s %s",
-                  session->id, push->initiating_id, nid,
-                  push->req->method, push->req->path);
+                  "h2_stream(%ld-%d): promised new stream %d for %s %s on %d",
+                  session->id, is->id, nid,
+                  push->req->method, push->req->path, is->id);
                   
     stream = h2_session_open_stream(session, nid);
     if (stream) {
         h2_stream_set_h2_request(stream, is->id, push->req);
-        h2_stream_set_priority(stream, &push->prio);
         status = stream_schedule(session, stream, 1);
         if (status != APR_SUCCESS) {
             ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, session->c,
@@ -1275,7 +1286,7 @@ struct h2_stream *h2_session_push(h2_session *session, h2_stream *is,
     else {
         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
                       "h2_stream(%ld-%d): failed to create stream obj %d",
-                      session->id, push->initiating_id, nid);
+                      session->id, is->id, nid);
     }
 
     if (!stream) {
@@ -1295,7 +1306,7 @@ static int valid_weight(float f)
 }
 
 apr_status_t h2_session_set_prio(h2_session *session, h2_stream *stream, 
-                                 h2_priority *prio)
+                                 const h2_priority *prio)
 {
     apr_status_t status = APR_SUCCESS;
 #ifdef H2_NG2_CHANGE_PRIO
@@ -1336,7 +1347,7 @@ apr_status_t h2_session_set_prio(h2_session *session, h2_stream *stream,
                  */
                 ptype = "INTERLEAVED";
                 w_parent = nghttp2_stream_get_weight(s_parent);
-                w = valid_weight(w_parent * ((float)NGHTTP2_MAX_WEIGHT / prio->weight));
+                w = valid_weight(w_parent * ((float)prio->weight / NGHTTP2_MAX_WEIGHT));
                 nghttp2_priority_spec_init(&ps, id_grandpa, w, 0);
                 break;
                 
@@ -1347,7 +1358,8 @@ apr_status_t h2_session_set_prio(h2_session *session, h2_stream *stream,
                  * stream as child with MAX_WEIGHT.
                  */
                 ptype = "BEFORE";
-                nghttp2_priority_spec_init(&ps, stream->id, NGHTTP2_MAX_WEIGHT, 0);
+                w_parent = nghttp2_stream_get_weight(s_parent);
+                nghttp2_priority_spec_init(&ps, stream->id, w_parent, 0);
                 rv = nghttp2_session_change_stream_priority(session->ngh2, id_parent, &ps);
                 if (rv < 0) {
                     ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
@@ -1357,8 +1369,8 @@ apr_status_t h2_session_set_prio(h2_session *session, h2_stream *stream,
                     return APR_EGENERAL;
                 }
                 id_grandpa = nghttp2_stream_get_stream_id(s_grandpa);
-                w_parent = nghttp2_stream_get_weight(s_parent);
-                nghttp2_priority_spec_init(&ps, id_grandpa, valid_weight(w_parent), 0);
+                w = valid_weight(w_parent * ((float)prio->weight / NGHTTP2_MAX_WEIGHT));
+                nghttp2_priority_spec_init(&ps, id_grandpa, w, 0);
                 break;
                 
             case H2_DEPENDANT_AFTER:
@@ -1508,12 +1520,43 @@ apr_status_t h2_session_process(h2_session *session)
     apr_interval_time_t wait_micros = 0;
     static const int MAX_WAIT_MICROS = 200 * 1000;
     int got_streams = 0;
+    h2_stream *stream;
 
     while (!session->aborted && (nghttp2_session_want_read(session->ngh2)
                                  || nghttp2_session_want_write(session->ngh2))) {
         int have_written = 0;
         int have_read = 0;
                                  
+        got_streams = !h2_stream_set_is_empty(session->streams);
+        if (got_streams) {            
+            h2_session_resume_streams_with_data(session);
+            
+            if (h2_stream_set_has_unsubmitted(session->streams)) {
+                /* If we have responses ready, submit them now. */
+                while ((stream = h2_mplx_next_submit(session->mplx, session->streams))) {
+                    status = submit_response(session, stream);
+                    if (status == APR_SUCCESS 
+                        && nghttp2_session_want_write(session->ngh2)) {
+                        int rv;
+                        
+                        rv = nghttp2_session_send(session->ngh2);
+                        if (rv != 0) {
+                            ap_log_cerror( APLOG_MARK, APLOG_DEBUG, 0, session->c,
+                                          "h2_session: send: %s", nghttp2_strerror(rv));
+                            if (nghttp2_is_fatal(rv)) {
+                                h2_session_abort(session, status, rv);
+                                goto end_process;
+                            }
+                        }
+                        else {
+                            have_written = 1;
+                            wait_micros = 0;
+                        }
+                    }
+                }
+            }
+        }
+        
         /* Send data as long as we have it and window sizes allow. We are
          * a server after all.
          */
@@ -1629,9 +1672,7 @@ apr_status_t h2_session_process(h2_session *session)
         }
         
         got_streams = !h2_stream_set_is_empty(session->streams);
-        if (got_streams) {
-            h2_stream *stream;
-            
+        if (got_streams) {            
             if (session->reprioritize) {
                 h2_mplx_reprioritize(session->mplx, stream_pri_cmp, session);
                 session->reprioritize = 0;
@@ -1657,15 +1698,6 @@ apr_status_t h2_session_process(h2_session *session)
                     h2_conn_io_flush(&session->io);
                 }
             }
-            
-            h2_session_resume_streams_with_data(session);
-            
-            if (h2_stream_set_has_unsubmitted(session->streams)) {
-                /* If we have responses ready, submit them now. */
-                while ((stream = h2_mplx_next_submit(session->mplx, session->streams))) {
-                    status = submit_response(session, stream);
-                }
-            }
         }
         
         if (have_written) {
index 16767fb785928a72da636b7cfe26d12d911184c2..00347c93e432359ad9c2b2f4b842948636217ac3 100644 (file)
@@ -59,6 +59,7 @@ struct h2_session {
     conn_rec *c;                    /* the connection this session serves */
     request_rec *r;                 /* the request that started this in case
                                      * of 'h2c', NULL otherwise */
+    const struct h2_config *config; /* Relevant config for this session */
     int aborted;                    /* this session is being aborted */
     int reprioritize;               /* scheduled streams priority needs to 
                                      * be re-evaluated */
@@ -94,7 +95,7 @@ struct h2_session {
  * @param workers the worker pool to use
  * @return the created session
  */
-h2_session *h2_session_create(conn_rec *c, struct h2_config *cfg, 
+h2_session *h2_session_create(conn_rec *c, const struct h2_config *cfg, 
                               struct h2_workers *workers);
 
 /**
@@ -105,7 +106,7 @@ h2_session *h2_session_create(conn_rec *c, struct h2_config *cfg,
  * @param workers the worker pool to use
  * @return the created session
  */
-h2_session *h2_session_rcreate(request_rec *r, struct h2_config *cfg,
+h2_session *h2_session_rcreate(request_rec *r, const struct h2_config *cfg,
                                struct h2_workers *workers);
 
 /**
@@ -198,7 +199,7 @@ struct h2_stream *h2_session_push(h2_session *session,
 
 apr_status_t h2_session_set_prio(h2_session *session, 
                                  struct h2_stream *stream, 
-                                 struct h2_priority *prio);
+                                 const struct h2_priority *prio);
 
 
 #endif /* defined(__mod_h2__h2_session__) */
index c9f88a27b6afa7f81d56a5cd90cded523328b46b..58f722bc645ccb3a2e32c92a5372ab5696b3fdda 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "h2_private.h"
 #include "h2_conn.h"
+#include "h2_config.h"
 #include "h2_h2.h"
 #include "h2_mplx.h"
 #include "h2_push.h"
@@ -159,7 +160,7 @@ h2_stream *h2_stream_open(int id, apr_pool_t *pool, h2_session *session)
 {
     h2_stream *stream = h2_stream_create(id, pool, session);
     set_state(stream, H2_STREAM_ST_OPEN);
-    stream->request   = h2_request_create(id, pool);
+    stream->request   = h2_request_create(id, pool, session->config);
     stream->bbout     = apr_brigade_create(stream->pool, 
                                            stream->session->c->bucket_alloc);
     
@@ -669,14 +670,15 @@ apr_table_t *h2_stream_get_trailers(h2_stream *stream)
     return stream->response? stream->response->trailers : NULL;
 }
 
-void h2_stream_set_priority(h2_stream *stream, h2_priority *prio)
+const h2_priority *h2_stream_get_priority(h2_stream *stream)
 {
-    stream->prio = apr_pcalloc(stream->pool, sizeof(*prio));
-    memcpy(stream->prio, prio, sizeof(*prio));
-}
-
-h2_priority *h2_stream_get_priority(h2_stream *stream)
-{
-    return stream->prio;
+    if (stream->initiated_on && stream->response) {
+        const char *ctype = apr_table_get(stream->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 NULL;
 }
 
index 8de3ecbacfcf618f72f0ba367a66a58d7dc77f7b..7b3eb3e7bca04f75f3c9692ca0381fd2ade6e8a9 100644 (file)
@@ -70,8 +70,6 @@ struct h2_stream {
     
     apr_bucket_brigade *bbout;  /* output DATA */
     apr_off_t data_frames_sent; /* # of DATA frames sent out for this stream */
-    
-    struct h2_priority *prio;   /* priority information to set before submit */
 };
 
 
@@ -306,13 +304,6 @@ apr_table_t *h2_stream_get_trailers(h2_stream *stream);
 /**
  * Get priority information set for this stream.
  */
-struct h2_priority *h2_stream_get_priority(h2_stream *stream);
-
-/**
- * Set the priority information to use on the submit of the stream.
- * @param stream the stream to set priority on
- * @param prio the priority information
- */
-void h2_stream_set_priority(h2_stream *stream, struct h2_priority *prio);
+const struct h2_priority *h2_stream_get_priority(h2_stream *stream);
 
 #endif /* defined(__mod_h2__h2_stream__) */
index c107db8e73a40eff93b42138663efbbd1985057a..49e5440624e51f08f376537943a906447b700478 100644 (file)
@@ -154,7 +154,7 @@ static int h2_protocol_switch(conn_rec *c, request_rec *r, server_rec *s,
             ap_remove_input_filter_byhandle(r->input_filters, "reqtimeout");
             
             /* Ok, start an h2_conn on this one. */
-            status = h2_conn_process(r->connection, r);
+            status = h2_conn_process(r->connection, r, r->server);
             if (status != DONE) {
                 /* Nothing really to do about this. */
                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r,
index fee406e1bbe45c3b962eb42f7c1382063d44bb44..55bcec7293480a682eaafbec5679a5b11b64ace6 100644 (file)
@@ -147,13 +147,13 @@ h2_task *h2_task_create(long session_id, const h2_request *req,
         return NULL;
     }
     
-    task->id = apr_psprintf(pool, "%ld-%d", session_id, req->id);
+    task->id        = apr_psprintf(pool, "%ld-%d", session_id, req->id);
     task->stream_id = req->id;
-    task->pool = pool;
-    task->mplx = mplx;
-    task->c = h2_conn_create(mplx->c, task->pool);
+    task->pool      = pool;
+    task->mplx      = mplx;
+    task->c         = h2_conn_create(mplx->c, task->pool);
 
-    task->request = req;
+    task->request   = req;
     task->input_eos = eos;    
     
     return task;
@@ -168,11 +168,10 @@ apr_status_t h2_task_destroy(h2_task *task)
 apr_status_t h2_task_do(h2_task *task, h2_worker *worker)
 {
     apr_status_t status = APR_SUCCESS;
-    h2_config *cfg = h2_config_get(task->mplx->c);
     
     AP_DEBUG_ASSERT(task);
     
-    task->serialize_headers = h2_config_geti(cfg, H2_CONF_SER_HEADERS);
+    task->serialize_headers = h2_config_geti(task->request->config, H2_CONF_SER_HEADERS);
 
     status = h2_worker_setup_task(worker, task);
     
index 7cf0f20de2af3a945c8a963d0ac0e71de4ef22c8..1cc32d647ce9a71b8c1694ad0e39542155473134 100644 (file)
@@ -66,7 +66,8 @@ struct h2_task {
 };
 
 h2_task *h2_task_create(long session_id, const struct h2_request *req, 
-                        apr_pool_t *pool, struct h2_mplx *mplx, int eos);
+                        apr_pool_t *pool, struct h2_mplx *mplx, 
+                        int eos);
 
 apr_status_t h2_task_destroy(h2_task *task);
 
index 950e43ff4a5dd6e1b8e26bf0af7ad3ca279f6b4f..cf05c0dc351e0284bacadb590b90d2ffdccf19d2 100644 (file)
@@ -20,7 +20,7 @@
  * @macro
  * Version number of the h2 module as c string
  */
-#define MOD_HTTP2_VERSION "1.0.7"
+#define MOD_HTTP2_VERSION "1.0.8"
 
 /**
  * @macro
@@ -28,7 +28,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 0x010007
+#define MOD_HTTP2_VERSION_NUM 0x010008
 
 
 #endif /* mod_h2_h2_version_h */