You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ic...@apache.org on 2019/03/13 15:00:58 UTC

svn commit: r1855431 [1/3] - in /httpd/httpd/branches/2.4.x: ./ docs/manual/mod/ modules/http2/

Author: icing
Date: Wed Mar 13 15:00:57 2019
New Revision: 1855431

URL: http://svn.apache.org/viewvc?rev=1855431&view=rev
Log:
Merge of 1849296,1852038,1852101,1852339,1853171,1853967,1854365,1854963,1854964,1855295,1855411 from trunk:

  *) mod_http2: when SSL renegotiation is inhibited and a 403 ErrorDocument is
     in play, the proper HTTP/2 stream reset did not trigger with H2_ERR_HTTP_1_1_REQUIRED.
     Fixed. [Michael Kaufmann] 

  *) mod_http2: new configuration directive: `H2Padding numbits` to control 
     padding of HTTP/2 payload frames. 'numbits' is a number from 0-8,
     controlling the range of padding bytes added to a frame. The actual number
     added is chosen randomly per frame. This applies to HEADERS, DATA and PUSH_PROMISE
     frames equally. The default continues to be 0, e.g. no padding. [Stefan Eissing] 
  
  *) mod_http2: ripping out all the h2_req_engine internal features now that mod_proxy_http2
     has no more need for it. Optional functions are still declared but no longer implemented.
     While previous mod_proxy_http2 will work with this, it is recommeneded to run the matching
     versions of both modules. [Stefan Eissing]
  
  *) mod_proxy_http2: changed mod_proxy_http2 implementation and fixed several bugs which
     resolve PR63170. The proxy module does now a single h2 request on the (reused)
     connection and returns. [Stefan Eissing]
  
  *) mod_http2/mod_proxy_http2: proxy_http2 checks correct master connection aborted status 
     to trigger immediate shutdown of backend connections. This is now always signalled
     by mod_http2 when the the session is being released. 
     proxy_http2 now only sends a PING frame to the backend when there is not already one
     in flight. [Stefan Eissing]

  *) mod_proxy_http2: fixed an issue where a proxy_http2 handler entered an infinite 
     loop when encountering certain errors on the backend connection. 
     See <https://bz.apache.org/bugzilla/show_bug.cgi?id=63170>. [Stefan Eissing]

  *) mod_http2: Configuration directives H2Push and H2Upgrade can now be specified per 
     Location/Directory, e.g. disabling PUSH for a specific set of resources. [Stefan Eissing]

  *) mod_http2: HEAD requests to some module such as mod_cgid caused the stream to
     terminate improperly and cause a HTTP/2 PROTOCOL_ERROR. 
     Fixes <https://github.com/icing/mod_h2/issues/167>. [Michael Kaufmann]



Modified:
    httpd/httpd/branches/2.4.x/CHANGES
    httpd/httpd/branches/2.4.x/docs/manual/mod/mod_http2.xml
    httpd/httpd/branches/2.4.x/modules/http2/config2.m4
    httpd/httpd/branches/2.4.x/modules/http2/h2.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_alt_svc.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_config.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_config.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_conn.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_conn.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_filter.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_from_h1.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_h2.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_h2.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_headers.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_ngn_shed.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_ngn_shed.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_proxy_session.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_proxy_session.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_request.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_session.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_session.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_stream.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_switch.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_task.c
    httpd/httpd/branches/2.4.x/modules/http2/h2_task.h
    httpd/httpd/branches/2.4.x/modules/http2/h2_version.h
    httpd/httpd/branches/2.4.x/modules/http2/mod_http2.c
    httpd/httpd/branches/2.4.x/modules/http2/mod_http2.h
    httpd/httpd/branches/2.4.x/modules/http2/mod_proxy_http2.c

Modified: httpd/httpd/branches/2.4.x/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/CHANGES?rev=1855431&r1=1855430&r2=1855431&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/CHANGES [utf-8] (original)
+++ httpd/httpd/branches/2.4.x/CHANGES [utf-8] Wed Mar 13 15:00:57 2019
@@ -1,6 +1,42 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.4.39
 
+  *) mod_http2: when SSL renegotiation is inhibited and a 403 ErrorDocument is
+     in play, the proper HTTP/2 stream reset did not trigger with H2_ERR_HTTP_1_1_REQUIRED.
+     Fixed. [Michael Kaufmann] 
+
+  *) mod_http2: new configuration directive: `H2Padding numbits` to control 
+     padding of HTTP/2 payload frames. 'numbits' is a number from 0-8,
+     controlling the range of padding bytes added to a frame. The actual number
+     added is chosen randomly per frame. This applies to HEADERS, DATA and PUSH_PROMISE
+     frames equally. The default continues to be 0, e.g. no padding. [Stefan Eissing] 
+  
+  *) mod_http2: ripping out all the h2_req_engine internal features now that mod_proxy_http2
+     has no more need for it. Optional functions are still declared but no longer implemented.
+     While previous mod_proxy_http2 will work with this, it is recommeneded to run the matching
+     versions of both modules. [Stefan Eissing]
+  
+  *) mod_proxy_http2: changed mod_proxy_http2 implementation and fixed several bugs which
+     resolve PR63170. The proxy module does now a single h2 request on the (reused)
+     connection and returns. [Stefan Eissing]
+  
+  *) mod_http2/mod_proxy_http2: proxy_http2 checks correct master connection aborted status 
+     to trigger immediate shutdown of backend connections. This is now always signalled
+     by mod_http2 when the the session is being released. 
+     proxy_http2 now only sends a PING frame to the backend when there is not already one
+     in flight. [Stefan Eissing]
+
+  *) mod_proxy_http2: fixed an issue where a proxy_http2 handler entered an infinite 
+     loop when encountering certain errors on the backend connection. 
+     See <https://bz.apache.org/bugzilla/show_bug.cgi?id=63170>. [Stefan Eissing]
+
+  *) mod_http2: Configuration directives H2Push and H2Upgrade can now be specified per 
+     Location/Directory, e.g. disabling PUSH for a specific set of resources. [Stefan Eissing]
+
+  *) mod_http2: HEAD requests to some module such as mod_cgid caused the stream to
+     terminate improperly and cause a HTTP/2 PROTOCOL_ERROR. 
+     Fixes <https://github.com/icing/mod_h2/issues/167>. [Michael Kaufmann]
+
   *) http: Fix possible empty response with mod_ratelimit for HEAD requests.
      PR 63192. [Yann Ylavic]
 

Modified: httpd/httpd/branches/2.4.x/docs/manual/mod/mod_http2.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/docs/manual/mod/mod_http2.xml?rev=1855431&r1=1855430&r2=1855431&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/docs/manual/mod/mod_http2.xml (original)
+++ httpd/httpd/branches/2.4.x/docs/manual/mod/mod_http2.xml Wed Mar 13 15:00:57 2019
@@ -244,6 +244,8 @@ H2Direct on
         <contextlist>
             <context>server config</context>
             <context>virtual host</context>
+            <context>directory</context>
+            <context>.htaccess</context>
         </contextlist>
         <compatibility>Available in version 2.4.18 and later.</compatibility>
         
@@ -269,7 +271,8 @@ H2Direct on
             </p>
             <p> 
                 Link headers in responses are either set by the application or
-                can be configured via <module>mod_headers</module> as:
+                can be configured via <directive>H2PushResource</directive> or
+                using <module>mod_headers</module> as:
             </p>
             <example><title>mod_headers example</title>
                 <highlight language="config">
@@ -286,9 +289,10 @@ H2Direct on
                 twice or more to one client. Use with care.
             </p>
             <p> 
-                HTTP/2 server pushes are enabled by default. This directive 
-                allows it to be switch off on all resources of this server/virtual
-                host.
+                HTTP/2 server pushes are enabled by default. On a server or virtual host,
+                you may enable/disable this feature for any connection to the host. In addition,
+                you may disable PUSH for a set of resources in a Directory/Location. This controls
+                which resources may cause a PUSH, not which resources may be sent via PUSH.
             </p>
             <example><title>Example</title>
                 <highlight language="config">
@@ -480,6 +484,8 @@ H2PushPriority text/css   interleaved
         <contextlist>
             <context>server config</context>
             <context>virtual host</context>
+            <context>directory</context>
+            <context>.htaccess</context>
         </contextlist>
         
         <usage>
@@ -938,4 +944,41 @@ H2TLSCoolDownSecs 0
         </usage>
     </directivesynopsis>
     
+    <directivesynopsis>
+        <name>H2Padding</name>
+        <description>Determine the range of padding bytes added to payload frames</description>
+        <syntax>H2Padding numbits</syntax>
+        <default>H2Padding 0</default>
+        <contextlist>
+            <context>server config</context>
+            <context>virtual host</context>
+        </contextlist>
+        <compatibility>Available in version 2.4.39 and later.</compatibility>
+        
+        <usage>
+            <p>
+                With the default 0, no padding bytes are added to any payload
+                frames, e.g. HEADERS, DATA and PUSH_PROMISE. This is the behaviour
+                of previous versions. It means that under certain conditions, an
+                observer of network traffic can see the length of those frames 
+                in the TLS stream.
+            </p>
+            <p>
+                When configuring numbits of 1-8, a random number in range
+                [0, 2^numbits[ are added to each frame. The random value is chosen
+                independantly for each frame that the module sends back to the client.
+            </p>
+            <p>
+                While more padding bytes give better message length obfuscation, they
+                are also additional traffic. The optimal number therefore depends on
+                the kind of web traffic the server carries.
+            </p>
+            <p>
+                The default of 0, e.g. no padding, was chosen for maximum backward
+                compatibility. There might be deployments where padding bytes are
+                unwanted or do harm. The most likely cause would be a client that
+                has a faults implementation.
+            </p>
+        </usage>
+    </directivesynopsis>
 </modulesynopsis>

Modified: httpd/httpd/branches/2.4.x/modules/http2/config2.m4
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/config2.m4?rev=1855431&r1=1855430&r2=1855431&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/config2.m4 (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/config2.m4 Wed Mar 13 15:00:57 2019
@@ -31,7 +31,6 @@ h2_from_h1.lo dnl
 h2_h2.lo dnl
 h2_headers.lo dnl
 h2_mplx.lo dnl
-h2_ngn_shed.lo dnl
 h2_push.lo dnl
 h2_request.lo dnl
 h2_session.lo dnl

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2.h?rev=1855431&r1=1855430&r2=1855431&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2.h Wed Mar 13 15:00:57 2019
@@ -48,12 +48,12 @@ extern const char *H2_MAGIC_TOKEN;
 #define H2_HEADER_PATH_LEN   5
 #define H2_CRLF             "\r\n"
 
-/* Max data size to write so it fits inside a TLS record */
-#define H2_DATA_CHUNK_SIZE          ((16*1024) - 100 - 9) 
-
 /* Size of the frame header itself in HTTP/2 */
 #define H2_FRAME_HDR_LEN            9
  
+/* Max data size to write so it fits inside a TLS record */
+#define H2_DATA_CHUNK_SIZE          ((16*1024) - 100 - H2_FRAME_HDR_LEN) 
+
 /* Maximum number of padding bytes in a frame, rfc7540 */
 #define H2_MAX_PADLEN               256
 /* Initial default window size, RFC 7540 ch. 6.5.2 */
@@ -162,5 +162,6 @@ typedef int h2_stream_pri_cmp(int stream
 #define H2_FILTER_DEBUG_NOTE    "http2-debug"
 #define H2_HDR_CONFORMANCE      "http2-hdr-conformance"
 #define H2_HDR_CONFORMANCE_UNSAFE      "unsafe"
+#define H2_PUSH_MODE_NOTE       "http2-push-mode"
 
 #endif /* defined(__mod_h2__h2__) */

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_alt_svc.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_alt_svc.c?rev=1855431&r1=1855430&r2=1855431&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_alt_svc.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_alt_svc.c Wed Mar 13 15:00:57 2019
@@ -75,7 +75,7 @@ h2_alt_svc *h2_alt_svc_parse(const char
 
 static int h2_alt_svc_handler(request_rec *r)
 {
-    const h2_config *cfg;
+    apr_array_header_t *alt_svcs;
     int i;
     
     if (r->connection->keepalives > 0) {
@@ -87,8 +87,8 @@ static int h2_alt_svc_handler(request_re
         return DECLINED;
     }
     
-    cfg = h2_config_sget(r->server);
-    if (r->hostname && cfg && cfg->alt_svcs && cfg->alt_svcs->nelts > 0) {
+    alt_svcs = h2_config_alt_svcs(r);
+    if (r->hostname && alt_svcs && alt_svcs->nelts > 0) {
         const char *alt_svc_used = apr_table_get(r->headers_in, "Alt-Svc-Used");
         if (!alt_svc_used) {
             /* We have alt-svcs defined and client is not already using
@@ -99,7 +99,7 @@ static int h2_alt_svc_handler(request_re
             const char *alt_svc = "";
             const char *svc_ma = "";
             int secure = h2_h2_is_tls(r->connection);
-            int ma = h2_config_geti(cfg, H2_CONF_ALT_SVC_MAX_AGE);
+            int ma = h2_config_rgeti(r, H2_CONF_ALT_SVC_MAX_AGE);
             if (ma >= 0) {
                 svc_ma = apr_psprintf(r->pool, "; ma=%d", ma);
             }
@@ -107,8 +107,8 @@ static int h2_alt_svc_handler(request_re
                           "h2_alt_svc: announce %s for %s:%d", 
                           (secure? "secure" : "insecure"), 
                           r->hostname, (int)r->server->port);
-            for (i = 0; i < cfg->alt_svcs->nelts; ++i) {
-                h2_alt_svc *as = h2_alt_svc_IDX(cfg->alt_svcs, i);
+            for (i = 0; i < alt_svcs->nelts; ++i) {
+                h2_alt_svc *as = h2_alt_svc_IDX(alt_svcs, i);
                 const char *ahost = as->host;
                 if (ahost && !apr_strnatcasecmp(ahost, r->hostname)) {
                     ahost = NULL;

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_config.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_config.c?rev=1855431&r1=1855430&r2=1855431&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_config.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_config.c Wed Mar 13 15:00:57 2019
@@ -42,6 +42,55 @@
 #define H2_CONFIG_GET(a, b, n) \
     (((a)->n == DEF_VAL)? (b) : (a))->n
 
+#define H2_CONFIG_SET(a, n, v) \
+    ((a)->n = v)
+
+#define CONFIG_CMD_SET(cmd,dir,var,val) \
+    h2_config_seti(((cmd)->path? (dir) : NULL), h2_config_sget((cmd)->server), var, val)
+
+#define CONFIG_CMD_SET64(cmd,dir,var,val) \
+    h2_config_seti64(((cmd)->path? (dir) : NULL), h2_config_sget((cmd)->server), var, val)
+
+/* Apache httpd module configuration for h2. */
+typedef struct h2_config {
+    const char *name;
+    int h2_max_streams;           /* max concurrent # streams (http2) */
+    int h2_window_size;           /* stream window size (http2) */
+    int min_workers;              /* min # of worker threads/child */
+    int max_workers;              /* max # of worker threads/child */
+    int max_worker_idle_secs;     /* max # of idle seconds for worker */
+    int stream_max_mem_size;      /* max # bytes held in memory/stream */
+    apr_array_header_t *alt_svcs; /* h2_alt_svc specs for this server */
+    int alt_svc_max_age;          /* seconds clients can rely on alt-svc info*/
+    int serialize_headers;        /* Use serialized HTTP/1.1 headers for 
+                                     processing, better compatibility */
+    int h2_direct;                /* if mod_h2 is active directly */
+    int modern_tls_only;          /* Accept only modern TLS in HTTP/2 connections */  
+    int h2_upgrade;               /* Allow HTTP/1 upgrade to h2/h2c */
+    apr_int64_t tls_warmup_size;  /* Amount of TLS data to send before going full write size */
+    int tls_cooldown_secs;        /* Seconds of idle time before going back to small TLS records */
+    int h2_push;                  /* if HTTP/2 server push is enabled */
+    struct apr_hash_t *priorities;/* map of content-type to h2_priority records */
+    
+    int push_diary_size;          /* # of entries in push diary */
+    int copy_files;               /* if files shall be copied vs setaside on output */
+    apr_array_header_t *push_list;/* list of h2_push_res configurations */
+    int early_hints;              /* support status code 103 */
+    int padding_bits;
+    int padding_always;
+} h2_config;
+
+typedef struct h2_dir_config {
+    const char *name;
+    apr_array_header_t *alt_svcs; /* h2_alt_svc specs for this server */
+    int alt_svc_max_age;          /* seconds clients can rely on alt-svc info*/
+    int h2_upgrade;               /* Allow HTTP/1 upgrade to h2/h2c */
+    int h2_push;                  /* if HTTP/2 server push is enabled */
+    apr_array_header_t *push_list;/* list of h2_push_res configurations */
+    int early_hints;              /* support status code 103 */
+} h2_dir_config;
+
+
 static h2_config defconf = {
     "default",
     100,                    /* max_streams */
@@ -64,6 +113,18 @@ static h2_config defconf = {
     0,                      /* copy files across threads */
     NULL,                   /* push list */
     0,                      /* early hints, http status 103 */
+    0,                      /* padding bits */
+    1,                      /* padding always */
+};
+
+static h2_dir_config defdconf = {
+    "default",
+    NULL,                   /* no alt-svcs */
+    -1,                     /* alt-svc max age */
+    -1,                     /* HTTP/1 Upgrade support */
+    -1,                     /* HTTP/2 server push enabled */
+    NULL,                   /* push list */
+    -1,                     /* early hints, http status 103 */
 };
 
 void h2_config_init(apr_pool_t *pool)
@@ -71,12 +132,10 @@ void h2_config_init(apr_pool_t *pool)
     (void)pool;
 }
 
-static void *h2_config_create(apr_pool_t *pool,
-                              const char *prefix, const char *x)
+void *h2_config_create_svr(apr_pool_t *pool, server_rec *s)
 {
     h2_config *conf = (h2_config *)apr_pcalloc(pool, sizeof(h2_config));
-    const char *s = x? x : "unknown";
-    char *name = apr_pstrcat(pool, prefix, "[", s, "]", NULL);
+    char *name = apr_pstrcat(pool, "srv[", s->defn_name, "]", NULL);
     
     conf->name                 = name;
     conf->h2_max_streams       = DEF_VAL;
@@ -98,19 +157,11 @@ static void *h2_config_create(apr_pool_t
     conf->copy_files           = DEF_VAL;
     conf->push_list            = NULL;
     conf->early_hints          = DEF_VAL;
+    conf->padding_bits         = DEF_VAL;
+    conf->padding_always       = DEF_VAL;
     return conf;
 }
 
-void *h2_config_create_svr(apr_pool_t *pool, server_rec *s)
-{
-    return h2_config_create(pool, "srv", s->defn_name);
-}
-
-void *h2_config_create_dir(apr_pool_t *pool, char *x)
-{
-    return h2_config_create(pool, "dir", x);
-}
-
 static void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv)
 {
     h2_config *base = (h2_config *)basev;
@@ -149,25 +200,52 @@ static void *h2_config_merge(apr_pool_t
         n->push_list        = add->push_list? add->push_list : base->push_list;
     }
     n->early_hints          = H2_CONFIG_GET(add, base, early_hints);
+    n->padding_bits         = H2_CONFIG_GET(add, base, padding_bits);
+    n->padding_always       = H2_CONFIG_GET(add, base, padding_always);
     return n;
 }
 
-void *h2_config_merge_dir(apr_pool_t *pool, void *basev, void *addv)
+void *h2_config_merge_svr(apr_pool_t *pool, void *basev, void *addv)
 {
     return h2_config_merge(pool, basev, addv);
 }
 
-void *h2_config_merge_svr(apr_pool_t *pool, void *basev, void *addv)
+void *h2_config_create_dir(apr_pool_t *pool, char *x)
 {
-    return h2_config_merge(pool, basev, addv);
+    h2_dir_config *conf = (h2_dir_config *)apr_pcalloc(pool, sizeof(h2_dir_config));
+    const char *s = x? x : "unknown";
+    char *name = apr_pstrcat(pool, "dir[", s, "]", NULL);
+    
+    conf->name                 = name;
+    conf->alt_svc_max_age      = DEF_VAL;
+    conf->h2_upgrade           = DEF_VAL;
+    conf->h2_push              = DEF_VAL;
+    conf->early_hints          = DEF_VAL;
+    return conf;
 }
 
-int h2_config_geti(const h2_config *conf, h2_config_var_t var)
+void *h2_config_merge_dir(apr_pool_t *pool, void *basev, void *addv)
 {
-    return (int)h2_config_geti64(conf, var);
+    h2_dir_config *base = (h2_dir_config *)basev;
+    h2_dir_config *add = (h2_dir_config *)addv;
+    h2_dir_config *n = (h2_dir_config *)apr_pcalloc(pool, sizeof(h2_dir_config));
+
+    n->name = apr_pstrcat(pool, "merged[", add->name, ", ", base->name, "]", NULL);
+    n->alt_svcs             = add->alt_svcs? add->alt_svcs : base->alt_svcs;
+    n->alt_svc_max_age      = H2_CONFIG_GET(add, base, alt_svc_max_age);
+    n->h2_upgrade           = H2_CONFIG_GET(add, base, h2_upgrade);
+    n->h2_push              = H2_CONFIG_GET(add, base, h2_push);
+    if (add->push_list && base->push_list) {
+        n->push_list        = apr_array_append(pool, base->push_list, add->push_list);
+    }
+    else {
+        n->push_list        = add->push_list? add->push_list : base->push_list;
+    }
+    n->early_hints          = H2_CONFIG_GET(add, base, early_hints);
+    return n;
 }
 
-apr_int64_t h2_config_geti64(const h2_config *conf, h2_config_var_t var)
+static apr_int64_t h2_srv_config_geti64(const h2_config *conf, h2_config_var_t var)
 {
     switch(var) {
         case H2_CONF_MAX_STREAMS:
@@ -191,7 +269,8 @@ apr_int64_t h2_config_geti64(const h2_co
         case H2_CONF_UPGRADE:
             return H2_CONFIG_GET(conf, &defconf, h2_upgrade);
         case H2_CONF_DIRECT:
-            return H2_CONFIG_GET(conf, &defconf, h2_direct);
+            return 1;
+            /*return H2_CONFIG_GET(conf, &defconf, h2_direct);*/
         case H2_CONF_TLS_WARMUP_SIZE:
             return H2_CONFIG_GET(conf, &defconf, tls_warmup_size);
         case H2_CONF_TLS_COOLDOWN_SECS:
@@ -204,12 +283,93 @@ apr_int64_t h2_config_geti64(const h2_co
             return H2_CONFIG_GET(conf, &defconf, copy_files);
         case H2_CONF_EARLY_HINTS:
             return H2_CONFIG_GET(conf, &defconf, early_hints);
+        case H2_CONF_PADDING_BITS:
+            return H2_CONFIG_GET(conf, &defconf, padding_bits);
+        case H2_CONF_PADDING_ALWAYS:
+            return H2_CONFIG_GET(conf, &defconf, padding_always);
         default:
             return DEF_VAL;
     }
 }
 
-const h2_config *h2_config_sget(server_rec *s)
+static void h2_srv_config_seti(h2_config *conf, h2_config_var_t var, int val)
+{
+    switch(var) {
+        case H2_CONF_MAX_STREAMS:
+            H2_CONFIG_SET(conf, h2_max_streams, val);
+            break;
+        case H2_CONF_WIN_SIZE:
+            H2_CONFIG_SET(conf, h2_window_size, val);
+            break;
+        case H2_CONF_MIN_WORKERS:
+            H2_CONFIG_SET(conf, min_workers, val);
+            break;
+        case H2_CONF_MAX_WORKERS:
+            H2_CONFIG_SET(conf, max_workers, val);
+            break;
+        case H2_CONF_MAX_WORKER_IDLE_SECS:
+            H2_CONFIG_SET(conf, max_worker_idle_secs, val);
+            break;
+        case H2_CONF_STREAM_MAX_MEM:
+            H2_CONFIG_SET(conf, stream_max_mem_size, val);
+            break;
+        case H2_CONF_ALT_SVC_MAX_AGE:
+            H2_CONFIG_SET(conf, alt_svc_max_age, val);
+            break;
+        case H2_CONF_SER_HEADERS:
+            H2_CONFIG_SET(conf, serialize_headers, val);
+            break;
+        case H2_CONF_MODERN_TLS_ONLY:
+            H2_CONFIG_SET(conf, modern_tls_only, val);
+            break;
+        case H2_CONF_UPGRADE:
+            H2_CONFIG_SET(conf, h2_upgrade, val);
+            break;
+        case H2_CONF_DIRECT:
+            H2_CONFIG_SET(conf, h2_direct, val);
+            break;
+        case H2_CONF_TLS_WARMUP_SIZE:
+            H2_CONFIG_SET(conf, tls_warmup_size, val);
+            break;
+        case H2_CONF_TLS_COOLDOWN_SECS:
+            H2_CONFIG_SET(conf, tls_cooldown_secs, val);
+            break;
+        case H2_CONF_PUSH:
+            H2_CONFIG_SET(conf, h2_push, val);
+            break;
+        case H2_CONF_PUSH_DIARY_SIZE:
+            H2_CONFIG_SET(conf, push_diary_size, val);
+            break;
+        case H2_CONF_COPY_FILES:
+            H2_CONFIG_SET(conf, copy_files, val);
+            break;
+        case H2_CONF_EARLY_HINTS:
+            H2_CONFIG_SET(conf, early_hints, val);
+            break;
+        case H2_CONF_PADDING_BITS:
+            H2_CONFIG_SET(conf, padding_bits, val);
+            break;
+        case H2_CONF_PADDING_ALWAYS:
+            H2_CONFIG_SET(conf, padding_always, val);
+            break;
+        default:
+            break;
+    }
+}
+
+static void h2_srv_config_seti64(h2_config *conf, h2_config_var_t var, apr_int64_t val)
+{
+    switch(var) {
+        case H2_CONF_TLS_WARMUP_SIZE:
+            H2_CONFIG_SET(conf, tls_warmup_size, val);
+            break;
+        default:
+            h2_srv_config_seti(conf, var, (int)val);
+            break;
+    }
+}
+
+static h2_config *h2_config_sget(server_rec *s)
 {
     h2_config *cfg = (h2_config *)ap_get_module_config(s->module_config, 
                                                        &http2_module);
@@ -217,9 +377,162 @@ const h2_config *h2_config_sget(server_r
     return cfg;
 }
 
-const struct h2_priority *h2_config_get_priority(const h2_config *conf, 
-                                                 const char *content_type)
+static const h2_dir_config *h2_config_rget(request_rec *r)
+{
+    h2_dir_config *cfg = (h2_dir_config *)ap_get_module_config(r->per_dir_config, 
+                                                               &http2_module);
+    ap_assert(cfg);
+    return cfg;
+}
+
+static apr_int64_t h2_dir_config_geti64(const h2_dir_config *conf, h2_config_var_t var)
+{
+    switch(var) {
+        case H2_CONF_ALT_SVC_MAX_AGE:
+            return H2_CONFIG_GET(conf, &defdconf, alt_svc_max_age);
+        case H2_CONF_UPGRADE:
+            return H2_CONFIG_GET(conf, &defdconf, h2_upgrade);
+        case H2_CONF_PUSH:
+            return H2_CONFIG_GET(conf, &defdconf, h2_push);
+        case H2_CONF_EARLY_HINTS:
+            return H2_CONFIG_GET(conf, &defdconf, early_hints);
+
+        default:
+            return DEF_VAL;
+    }
+}
+
+static void h2_config_seti(h2_dir_config *dconf, h2_config *conf, h2_config_var_t var, int val)
+{
+    int set_srv = !dconf;
+    if (dconf) {
+        switch(var) {
+            case H2_CONF_ALT_SVC_MAX_AGE:
+                H2_CONFIG_SET(dconf, alt_svc_max_age, val);
+                break;
+            case H2_CONF_UPGRADE:
+                H2_CONFIG_SET(dconf, h2_upgrade, val);
+                break;
+            case H2_CONF_PUSH:
+                H2_CONFIG_SET(dconf, h2_push, val);
+                break;
+            case H2_CONF_EARLY_HINTS:
+                H2_CONFIG_SET(dconf, early_hints, val);
+                break;
+            default:
+                /* not handled in dir_conf */
+                set_srv = 1;
+                break;
+        }
+    }
+
+    if (set_srv) {
+        h2_srv_config_seti(conf, var, val);
+    }
+}
+
+static void h2_config_seti64(h2_dir_config *dconf, h2_config *conf, h2_config_var_t var, apr_int64_t val)
 {
+    int set_srv = !dconf;
+    if (dconf) {
+        switch(var) {
+            default:
+                /* not handled in dir_conf */
+                set_srv = 1;
+                break;
+        }
+    }
+
+    if (set_srv) {
+        h2_srv_config_seti64(conf, var, val);
+    }
+}
+
+static const h2_config *h2_config_get(conn_rec *c)
+{
+    h2_ctx *ctx = h2_ctx_get(c, 0);
+    
+    if (ctx) {
+        if (ctx->config) {
+            return ctx->config;
+        }
+        else if (ctx->server) {
+            ctx->config = h2_config_sget(ctx->server);
+            return ctx->config;
+        }
+    }
+    
+    return h2_config_sget(c->base_server);
+}
+
+int h2_config_cgeti(conn_rec *c, h2_config_var_t var)
+{
+    return (int)h2_srv_config_geti64(h2_config_get(c), var);
+}
+
+apr_int64_t h2_config_cgeti64(conn_rec *c, h2_config_var_t var)
+{
+    return h2_srv_config_geti64(h2_config_get(c), var);
+}
+
+int h2_config_sgeti(server_rec *s, h2_config_var_t var)
+{
+    return (int)h2_srv_config_geti64(h2_config_sget(s), var);
+}
+
+apr_int64_t h2_config_sgeti64(server_rec *s, h2_config_var_t var)
+{
+    return h2_srv_config_geti64(h2_config_sget(s), var);
+}
+
+int h2_config_geti(request_rec *r, server_rec *s, h2_config_var_t var)
+{
+    return (int)h2_config_geti64(r, s, var);
+}
+
+apr_int64_t h2_config_geti64(request_rec *r, server_rec *s, h2_config_var_t var)
+{
+    apr_int64_t mode = r? (int)h2_dir_config_geti64(h2_config_rget(r), var) : DEF_VAL;
+    return (mode != DEF_VAL)? mode : h2_config_sgeti64(s, var);
+}
+
+int h2_config_rgeti(request_rec *r, h2_config_var_t var)
+{
+    return h2_config_geti(r, r->server, var);
+}
+
+apr_int64_t h2_config_rgeti64(request_rec *r, h2_config_var_t var)
+{
+    return h2_config_geti64(r, r->server, var);
+}
+
+apr_array_header_t *h2_config_push_list(request_rec *r)
+{
+    const h2_config *sconf;
+    const h2_dir_config *conf = h2_config_rget(r);
+    
+    if (conf && conf->push_list) {
+        return conf->push_list;
+    }
+    sconf = h2_config_sget(r->server); 
+    return sconf? sconf->push_list : NULL;
+}
+
+apr_array_header_t *h2_config_alt_svcs(request_rec *r)
+{
+    const h2_config *sconf;
+    const h2_dir_config *conf = h2_config_rget(r);
+    
+    if (conf && conf->alt_svcs) {
+        return conf->alt_svcs;
+    }
+    sconf = h2_config_sget(r->server); 
+    return sconf? sconf->alt_svcs : NULL;
+}
+
+const struct h2_priority *h2_cconfig_get_priority(conn_rec *c, const char *content_type)
+{
+    const h2_config *conf = h2_config_get(c);
     if (content_type && conf->priorities) {
         size_t len = strcspn(content_type, "; \t");
         h2_priority *prio = apr_hash_get(conf->priorities, content_type, len);
@@ -228,166 +541,156 @@ const struct h2_priority *h2_config_get_
     return NULL;
 }
 
-static const char *h2_conf_set_max_streams(cmd_parms *parms,
-                                           void *arg, const char *value)
+static const char *h2_conf_set_max_streams(cmd_parms *cmd,
+                                           void *dirconf, const char *value)
 {
-    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
-    cfg->h2_max_streams = (int)apr_atoi64(value);
-    (void)arg;
-    if (cfg->h2_max_streams < 1) {
+    apr_int64_t ival = (int)apr_atoi64(value);
+    if (ival < 1) {
         return "value must be > 0";
     }
+    CONFIG_CMD_SET64(cmd, dirconf, H2_CONF_MAX_STREAMS, ival);
     return NULL;
 }
 
-static const char *h2_conf_set_window_size(cmd_parms *parms,
-                                           void *arg, const char *value)
+static const char *h2_conf_set_window_size(cmd_parms *cmd,
+                                           void *dirconf, const char *value)
 {
-    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
-    cfg->h2_window_size = (int)apr_atoi64(value);
-    (void)arg;
-    if (cfg->h2_window_size < 1024) {
+    int val = (int)apr_atoi64(value);
+    if (val < 1024) {
         return "value must be >= 1024";
     }
+    CONFIG_CMD_SET(cmd, dirconf, H2_CONF_WIN_SIZE, val);
     return NULL;
 }
 
-static const char *h2_conf_set_min_workers(cmd_parms *parms,
-                                           void *arg, const char *value)
+static const char *h2_conf_set_min_workers(cmd_parms *cmd,
+                                           void *dirconf, const char *value)
 {
-    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
-    cfg->min_workers = (int)apr_atoi64(value);
-    (void)arg;
-    if (cfg->min_workers < 1) {
+    int val = (int)apr_atoi64(value);
+    if (val < 1) {
         return "value must be > 0";
     }
+    CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MIN_WORKERS, val);
     return NULL;
 }
 
-static const char *h2_conf_set_max_workers(cmd_parms *parms,
-                                           void *arg, const char *value)
+static const char *h2_conf_set_max_workers(cmd_parms *cmd,
+                                           void *dirconf, const char *value)
 {
-    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
-    cfg->max_workers = (int)apr_atoi64(value);
-    (void)arg;
-    if (cfg->max_workers < 1) {
+    int val = (int)apr_atoi64(value);
+    if (val < 1) {
         return "value must be > 0";
     }
+    CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MAX_WORKERS, val);
     return NULL;
 }
 
-static const char *h2_conf_set_max_worker_idle_secs(cmd_parms *parms,
-                                                    void *arg, const char *value)
+static const char *h2_conf_set_max_worker_idle_secs(cmd_parms *cmd,
+                                                    void *dirconf, const char *value)
 {
-    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
-    cfg->max_worker_idle_secs = (int)apr_atoi64(value);
-    (void)arg;
-    if (cfg->max_worker_idle_secs < 1) {
+    int val = (int)apr_atoi64(value);
+    if (val < 1) {
         return "value must be > 0";
     }
+    CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MAX_WORKER_IDLE_SECS, val);
     return NULL;
 }
 
-static const char *h2_conf_set_stream_max_mem_size(cmd_parms *parms,
-                                                   void *arg, const char *value)
+static const char *h2_conf_set_stream_max_mem_size(cmd_parms *cmd,
+                                                   void *dirconf, const char *value)
 {
-    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
-    
-    
-    cfg->stream_max_mem_size = (int)apr_atoi64(value);
-    (void)arg;
-    if (cfg->stream_max_mem_size < 1024) {
+    int val = (int)apr_atoi64(value);
+    if (val < 1024) {
         return "value must be >= 1024";
     }
+    CONFIG_CMD_SET(cmd, dirconf, H2_CONF_STREAM_MAX_MEM, val);
     return NULL;
 }
 
-static const char *h2_add_alt_svc(cmd_parms *parms,
-                                  void *arg, const char *value)
+static const char *h2_add_alt_svc(cmd_parms *cmd,
+                                  void *dirconf, const char *value)
 {
     if (value && *value) {
-        h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
-        h2_alt_svc *as = h2_alt_svc_parse(value, parms->pool);
+        h2_alt_svc *as = h2_alt_svc_parse(value, cmd->pool);
         if (!as) {
             return "unable to parse alt-svc specifier";
         }
-        if (!cfg->alt_svcs) {
-            cfg->alt_svcs = apr_array_make(parms->pool, 5, sizeof(h2_alt_svc*));
+
+        if (cmd->path) {
+            h2_dir_config *dcfg = (h2_dir_config *)dirconf;
+            if (!dcfg->alt_svcs) {
+                dcfg->alt_svcs = apr_array_make(cmd->pool, 5, sizeof(h2_alt_svc*));
+            }
+            APR_ARRAY_PUSH(dcfg->alt_svcs, h2_alt_svc*) = as;
+        }
+        else {
+            h2_config *cfg = (h2_config *)h2_config_sget(cmd->server);
+            if (!cfg->alt_svcs) {
+                cfg->alt_svcs = apr_array_make(cmd->pool, 5, sizeof(h2_alt_svc*));
+            }
+            APR_ARRAY_PUSH(cfg->alt_svcs, h2_alt_svc*) = as;
         }
-        APR_ARRAY_PUSH(cfg->alt_svcs, h2_alt_svc*) = as;
     }
-    (void)arg;
     return NULL;
 }
 
-static const char *h2_conf_set_alt_svc_max_age(cmd_parms *parms,
-                                               void *arg, const char *value)
+static const char *h2_conf_set_alt_svc_max_age(cmd_parms *cmd,
+                                               void *dirconf, const char *value)
 {
-    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
-    cfg->alt_svc_max_age = (int)apr_atoi64(value);
-    (void)arg;
+    int val = (int)apr_atoi64(value);
+    CONFIG_CMD_SET(cmd, dirconf, H2_CONF_ALT_SVC_MAX_AGE, val);
     return NULL;
 }
 
-static const char *h2_conf_set_session_extra_files(cmd_parms *parms,
-                                                   void *arg, const char *value)
+static const char *h2_conf_set_session_extra_files(cmd_parms *cmd,
+                                                   void *dirconf, const char *value)
 {
     /* deprecated, ignore */
-    (void)arg;
+    (void)dirconf;
     (void)value;
-    ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, parms->pool, /* NO LOGNO */
+    ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, cmd->pool, /* NO LOGNO */
                   "H2SessionExtraFiles is obsolete and will be ignored");
     return NULL;
 }
 
-static const char *h2_conf_set_serialize_headers(cmd_parms *parms,
-                                                 void *arg, const char *value)
+static const char *h2_conf_set_serialize_headers(cmd_parms *cmd,
+                                                 void *dirconf, const char *value)
 {
-    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
     if (!strcasecmp(value, "On")) {
-        cfg->serialize_headers = 1;
+        CONFIG_CMD_SET(cmd, dirconf, H2_CONF_SER_HEADERS, 1);
         return NULL;
     }
     else if (!strcasecmp(value, "Off")) {
-        cfg->serialize_headers = 0;
+        CONFIG_CMD_SET(cmd, dirconf, H2_CONF_SER_HEADERS, 0);
         return NULL;
     }
-    
-    (void)arg;
     return "value must be On or Off";
 }
 
-static const char *h2_conf_set_direct(cmd_parms *parms,
-                                      void *arg, const char *value)
+static const char *h2_conf_set_direct(cmd_parms *cmd,
+                                      void *dirconf, const char *value)
 {
-    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
     if (!strcasecmp(value, "On")) {
-        cfg->h2_direct = 1;
+        CONFIG_CMD_SET(cmd, dirconf, H2_CONF_DIRECT, 1);
         return NULL;
     }
     else if (!strcasecmp(value, "Off")) {
-        cfg->h2_direct = 0;
+        CONFIG_CMD_SET(cmd, dirconf, H2_CONF_DIRECT, 0);
         return NULL;
     }
-    
-    (void)arg;
     return "value must be On or Off";
 }
 
-static const char *h2_conf_set_push(cmd_parms *parms,
-                                    void *arg, const char *value)
+static const char *h2_conf_set_push(cmd_parms *cmd, void *dirconf, const char *value)
 {
-    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
     if (!strcasecmp(value, "On")) {
-        cfg->h2_push = 1;
+        CONFIG_CMD_SET(cmd, dirconf, H2_CONF_PUSH, 1);
         return NULL;
     }
     else if (!strcasecmp(value, "Off")) {
-        cfg->h2_push = 0;
+        CONFIG_CMD_SET(cmd, dirconf, H2_CONF_PUSH, 0);
         return NULL;
     }
-    
-    (void)arg;
     return "value must be On or Off";
 }
 
@@ -447,100 +750,88 @@ static const char *h2_conf_add_push_prio
     return NULL;
 }
 
-static const char *h2_conf_set_modern_tls_only(cmd_parms *parms,
-                                               void *arg, const char *value)
+static const char *h2_conf_set_modern_tls_only(cmd_parms *cmd,
+                                               void *dirconf, const char *value)
 {
-    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
     if (!strcasecmp(value, "On")) {
-        cfg->modern_tls_only = 1;
+        CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MODERN_TLS_ONLY, 1);
         return NULL;
     }
     else if (!strcasecmp(value, "Off")) {
-        cfg->modern_tls_only = 0;
+        CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MODERN_TLS_ONLY, 0);
         return NULL;
     }
-    
-    (void)arg;
     return "value must be On or Off";
 }
 
-static const char *h2_conf_set_upgrade(cmd_parms *parms,
-                                       void *arg, const char *value)
+static const char *h2_conf_set_upgrade(cmd_parms *cmd,
+                                       void *dirconf, const char *value)
 {
-    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
     if (!strcasecmp(value, "On")) {
-        cfg->h2_upgrade = 1;
+        CONFIG_CMD_SET(cmd, dirconf, H2_CONF_UPGRADE, 1);
         return NULL;
     }
     else if (!strcasecmp(value, "Off")) {
-        cfg->h2_upgrade = 0;
+        CONFIG_CMD_SET(cmd, dirconf, H2_CONF_UPGRADE, 0);
         return NULL;
     }
-    
-    (void)arg;
     return "value must be On or Off";
 }
 
-static const char *h2_conf_set_tls_warmup_size(cmd_parms *parms,
-                                               void *arg, const char *value)
+static const char *h2_conf_set_tls_warmup_size(cmd_parms *cmd,
+                                               void *dirconf, const char *value)
 {
-    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
-    cfg->tls_warmup_size = apr_atoi64(value);
-    (void)arg;
+    apr_int64_t val = apr_atoi64(value);
+    CONFIG_CMD_SET64(cmd, dirconf, H2_CONF_TLS_WARMUP_SIZE, val);
     return NULL;
 }
 
-static const char *h2_conf_set_tls_cooldown_secs(cmd_parms *parms,
-                                                 void *arg, const char *value)
+static const char *h2_conf_set_tls_cooldown_secs(cmd_parms *cmd,
+                                                 void *dirconf, const char *value)
 {
-    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
-    cfg->tls_cooldown_secs = (int)apr_atoi64(value);
-    (void)arg;
+    apr_int64_t val = (int)apr_atoi64(value);
+    CONFIG_CMD_SET64(cmd, dirconf, H2_CONF_TLS_COOLDOWN_SECS, val);
     return NULL;
 }
 
-static const char *h2_conf_set_push_diary_size(cmd_parms *parms,
-                                               void *arg, const char *value)
+static const char *h2_conf_set_push_diary_size(cmd_parms *cmd,
+                                               void *dirconf, const char *value)
 {
-    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
-    (void)arg;
-    cfg->push_diary_size = (int)apr_atoi64(value);
-    if (cfg->push_diary_size < 0) {
+    int val = (int)apr_atoi64(value);
+    if (val < 0) {
         return "value must be >= 0";
     }
-    if (cfg->push_diary_size > 0 && (cfg->push_diary_size & (cfg->push_diary_size-1))) {
+    if (val > 0 && (val & (val-1))) {
         return "value must a power of 2";
     }
-    if (cfg->push_diary_size > (1 << 15)) {
+    if (val > (1 << 15)) {
         return "value must <= 65536";
     }
+    CONFIG_CMD_SET(cmd, dirconf, H2_CONF_PUSH_DIARY_SIZE, val);
     return NULL;
 }
 
-static const char *h2_conf_set_copy_files(cmd_parms *parms,
-                                          void *arg, const char *value)
+static const char *h2_conf_set_copy_files(cmd_parms *cmd,
+                                          void *dirconf, const char *value)
 {
-    h2_config *cfg = (h2_config *)arg;
     if (!strcasecmp(value, "On")) {
-        cfg->copy_files = 1;
+        CONFIG_CMD_SET(cmd, dirconf, H2_CONF_COPY_FILES, 1);
         return NULL;
     }
     else if (!strcasecmp(value, "Off")) {
-        cfg->copy_files = 0;
+        CONFIG_CMD_SET(cmd, dirconf, H2_CONF_COPY_FILES, 0);
         return NULL;
     }
-    
-    (void)arg;
     return "value must be On or Off";
 }
 
-static void add_push(apr_pool_t *pool, h2_config *conf, h2_push_res *push)
+static void add_push(apr_array_header_t **plist, apr_pool_t *pool, h2_push_res *push)
 {
     h2_push_res *new;
-    if (!conf->push_list) {
-        conf->push_list = apr_array_make(pool, 10, sizeof(*push));
+    if (!*plist) {
+        *plist = apr_array_make(pool, 10, sizeof(*push));
     }
-    new = apr_array_push(conf->push_list);
+    new = apr_array_push(*plist);
     new->uri_ref = push->uri_ref;
     new->critical = push->critical;
 }
@@ -549,8 +840,6 @@ static const char *h2_conf_add_push_res(
                                         const char *arg1, const char *arg2,
                                         const char *arg3)
 {
-    h2_config *dconf = (h2_config*)dirconf ;
-    h2_config *sconf = (h2_config*)h2_config_sget(cmd->server);
     h2_push_res push;
     const char *last = arg3;
     
@@ -575,42 +864,54 @@ static const char *h2_conf_add_push_res(
         }
     }
 
-    /* server command? set both */
-    if (cmd->path == NULL) {
-        add_push(cmd->pool, sconf, &push);
-        add_push(cmd->pool, dconf, &push);
+    if (cmd->path) {
+        add_push(&(((h2_dir_config*)dirconf)->push_list), cmd->pool, &push);
     }
     else {
-        add_push(cmd->pool, dconf, &push);
+        add_push(&(h2_config_sget(cmd->server)->push_list), cmd->pool, &push);
     }
+    return NULL;
+}
 
+static const char *h2_conf_set_early_hints(cmd_parms *cmd,
+                                           void *dirconf, const char *value)
+{
+    int val;
+
+    if (!strcasecmp(value, "On")) val = 1;
+    else if (!strcasecmp(value, "Off")) val = 0;
+    else return "value must be On or Off";
+    
+    CONFIG_CMD_SET(cmd, dirconf, H2_CONF_EARLY_HINTS, val);
+    if (cmd->path) {
+        ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, cmd->pool, 
+                            "H2EarlyHints = %d on path %s", val, cmd->path);
+    }
     return NULL;
 }
 
-static const char *h2_conf_set_early_hints(cmd_parms *parms,
-                                           void *arg, const char *value)
+static const char *h2_conf_set_padding(cmd_parms *cmd, void *dirconf, const char *value)
 {
-    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
-    if (!strcasecmp(value, "On")) {
-        cfg->early_hints = 1;
-        return NULL;
+    int val;
+    
+    val = (int)apr_atoi64(value);
+    if (val < 0) {
+        return "number of bits must be >= 0";
     }
-    else if (!strcasecmp(value, "Off")) {
-        cfg->early_hints = 0;
-        return NULL;
+    if (val > 8) {
+        return "number of bits must be <= 8";
     }
-    
-    (void)arg;
-    return "value must be On or Off";
+    CONFIG_CMD_SET(cmd, dirconf, H2_CONF_PADDING_BITS, val);
+    return NULL;
 }
 
+
 void h2_get_num_workers(server_rec *s, int *minw, int *maxw)
 {
     int threads_per_child = 0;
-    const h2_config *config = h2_config_sget(s);
 
-    *minw = h2_config_geti(config, H2_CONF_MIN_WORKERS);
-    *maxw = h2_config_geti(config, H2_CONF_MAX_WORKERS);    
+    *minw = h2_config_sgeti(s, H2_CONF_MIN_WORKERS);
+    *maxw = h2_config_sgeti(s, H2_CONF_MAX_WORKERS);    
     ap_mpm_query(AP_MPMQ_MAX_THREADS, &threads_per_child);
 
     if (*minw <= 0) {
@@ -652,7 +953,7 @@ const command_rec h2_cmds[] = {
     AP_INIT_TAKE1("H2ModernTLSOnly", h2_conf_set_modern_tls_only, NULL,
                   RSRC_CONF, "off to not impose RFC 7540 restrictions on TLS"),
     AP_INIT_TAKE1("H2Upgrade", h2_conf_set_upgrade, NULL,
-                  RSRC_CONF, "on to allow HTTP/1 Upgrades to h2/h2c"),
+                  RSRC_CONF|OR_AUTHCFG, "on to allow HTTP/1 Upgrades to h2/h2c"),
     AP_INIT_TAKE1("H2Direct", h2_conf_set_direct, NULL,
                   RSRC_CONF, "on to enable direct HTTP/2 mode"),
     AP_INIT_TAKE1("H2SessionExtraFiles", h2_conf_set_session_extra_files, NULL,
@@ -662,7 +963,7 @@ const command_rec h2_cmds[] = {
     AP_INIT_TAKE1("H2TLSCoolDownSecs", h2_conf_set_tls_cooldown_secs, NULL,
                   RSRC_CONF, "seconds of idle time on TLS before shrinking writes"),
     AP_INIT_TAKE1("H2Push", h2_conf_set_push, NULL,
-                  RSRC_CONF, "off to disable HTTP/2 server push"),
+                  RSRC_CONF|OR_AUTHCFG, "off to disable HTTP/2 server push"),
     AP_INIT_TAKE23("H2PushPriority", h2_conf_add_push_priority, NULL,
                   RSRC_CONF, "define priority of PUSHed resources per content type"),
     AP_INIT_TAKE1("H2PushDiarySize", h2_conf_set_push_diary_size, NULL,
@@ -670,33 +971,12 @@ const command_rec h2_cmds[] = {
     AP_INIT_TAKE1("H2CopyFiles", h2_conf_set_copy_files, NULL,
                   OR_FILEINFO, "on to perform copy of file data"),
     AP_INIT_TAKE123("H2PushResource", h2_conf_add_push_res, NULL,
-                   OR_FILEINFO, "add a resource to be pushed in this location/on this server."),
+                   OR_FILEINFO|OR_AUTHCFG, "add a resource to be pushed in this location/on this server."),
     AP_INIT_TAKE1("H2EarlyHints", h2_conf_set_early_hints, NULL,
                   RSRC_CONF, "on to enable interim status 103 responses"),
+    AP_INIT_TAKE1("H2Padding", h2_conf_set_padding, NULL,
+                  RSRC_CONF, "set payload padding"),
     AP_END_CMD
 };
 
 
-const h2_config *h2_config_rget(request_rec *r)
-{
-    h2_config *cfg = (h2_config *)ap_get_module_config(r->per_dir_config, 
-                                                       &http2_module);
-    return cfg? cfg : h2_config_sget(r->server); 
-}
-
-const h2_config *h2_config_get(conn_rec *c)
-{
-    h2_ctx *ctx = h2_ctx_get(c, 0);
-    
-    if (ctx) {
-        if (ctx->config) {
-            return ctx->config;
-        }
-        else if (ctx->server) {
-            ctx->config = h2_config_sget(ctx->server);
-            return ctx->config;
-        }
-    }
-    
-    return h2_config_sget(c->base_server);
-}

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_config.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_config.h?rev=1855431&r1=1855430&r2=1855431&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_config.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_config.h Wed Mar 13 15:00:57 2019
@@ -42,6 +42,8 @@ typedef enum {
     H2_CONF_PUSH_DIARY_SIZE,
     H2_CONF_COPY_FILES,
     H2_CONF_EARLY_HINTS,
+    H2_CONF_PADDING_BITS,
+    H2_CONF_PADDING_ALWAYS,
 } h2_config_var_t;
 
 struct apr_hash_t;
@@ -53,33 +55,6 @@ typedef struct h2_push_res {
     int critical;
 } h2_push_res;
 
-/* Apache httpd module configuration for h2. */
-typedef struct h2_config {
-    const char *name;
-    int h2_max_streams;           /* max concurrent # streams (http2) */
-    int h2_window_size;           /* stream window size (http2) */
-    int min_workers;              /* min # of worker threads/child */
-    int max_workers;              /* max # of worker threads/child */
-    int max_worker_idle_secs;     /* max # of idle seconds for worker */
-    int stream_max_mem_size;      /* max # bytes held in memory/stream */
-    apr_array_header_t *alt_svcs; /* h2_alt_svc specs for this server */
-    int alt_svc_max_age;          /* seconds clients can rely on alt-svc info*/
-    int serialize_headers;        /* Use serialized HTTP/1.1 headers for 
-                                     processing, better compatibility */
-    int h2_direct;                /* if mod_h2 is active directly */
-    int modern_tls_only;          /* Accept only modern TLS in HTTP/2 connections */  
-    int h2_upgrade;               /* Allow HTTP/1 upgrade to h2/h2c */
-    apr_int64_t tls_warmup_size;  /* Amount of TLS data to send before going full write size */
-    int tls_cooldown_secs;        /* Seconds of idle time before going back to small TLS records */
-    int h2_push;                  /* if HTTP/2 server push is enabled */
-    struct apr_hash_t *priorities;/* map of content-type to h2_priority records */
-    
-    int push_diary_size;          /* # of entries in push diary */
-    int copy_files;               /* if files shall be copied vs setaside on output */
-    apr_array_header_t *push_list;/* list of h2_push_res configurations */
-    int early_hints;              /* support status code 103 */
-} h2_config;
-
 
 void *h2_config_create_dir(apr_pool_t *pool, char *x);
 void *h2_config_merge_dir(apr_pool_t *pool, void *basev, void *addv);
@@ -88,19 +63,37 @@ void *h2_config_merge_svr(apr_pool_t *po
 
 extern const command_rec h2_cmds[];
 
-const h2_config *h2_config_get(conn_rec *c);
-const h2_config *h2_config_sget(server_rec *s);
-const h2_config *h2_config_rget(request_rec *r);
+int h2_config_geti(request_rec *r, server_rec *s, h2_config_var_t var);
+apr_int64_t h2_config_geti64(request_rec *r, server_rec *s, h2_config_var_t var);
 
-int h2_config_geti(const h2_config *conf, h2_config_var_t var);
-apr_int64_t h2_config_geti64(const h2_config *conf, h2_config_var_t var);
+/** 
+ * Get the configured value for variable <var> at the given connection.
+ */
+int h2_config_cgeti(conn_rec *c, h2_config_var_t var);
+apr_int64_t h2_config_cgeti64(conn_rec *c, h2_config_var_t var);
+
+/** 
+ * Get the configured value for variable <var> at the given server.
+ */
+int h2_config_sgeti(server_rec *s, h2_config_var_t var);
+apr_int64_t h2_config_sgeti64(server_rec *s, h2_config_var_t var);
+
+/** 
+ * Get the configured value for variable <var> at the given request,
+ * if configured for the request location. 
+ * Fallback to request server config otherwise.
+ */
+int h2_config_rgeti(request_rec *r, h2_config_var_t var);
+apr_int64_t h2_config_rgeti64(request_rec *r, h2_config_var_t var);
 
-void h2_get_num_workers(server_rec *s, int *minw, int *maxw);
+apr_array_header_t *h2_config_push_list(request_rec *r);
+apr_array_header_t *h2_config_alt_svcs(request_rec *r);
 
+
+void h2_get_num_workers(server_rec *s, int *minw, int *maxw);
 void h2_config_init(apr_pool_t *pool);
 
-const struct h2_priority *h2_config_get_priority(const h2_config *conf, 
-                                                 const char *content_type);
+const struct h2_priority *h2_cconfig_get_priority(conn_rec *c, const char *content_type);
        
 #endif /* __mod_h2__h2_config_h__ */
 

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_conn.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_conn.c?rev=1855431&r1=1855430&r2=1855431&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_conn.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_conn.c Wed Mar 13 15:00:57 2019
@@ -18,6 +18,7 @@
 #include <apr_strings.h>
 
 #include <ap_mpm.h>
+#include <ap_mmn.h>
 
 #include <httpd.h>
 #include <http_core.h>
@@ -109,7 +110,6 @@ static void check_modules(int force)
 
 apr_status_t h2_conn_child_init(apr_pool_t *pool, server_rec *s)
 {
-    const h2_config *config = h2_config_sget(s);
     apr_status_t status = APR_SUCCESS;
     int minw, maxw;
     int max_threads_per_child = 0;
@@ -129,7 +129,7 @@ apr_status_t h2_conn_child_init(apr_pool
     
     h2_get_num_workers(s, &minw, &maxw);
     
-    idle_secs = h2_config_geti(config, H2_CONF_MAX_WORKER_IDLE_SECS);
+    idle_secs = h2_config_sgeti(s, H2_CONF_MAX_WORKER_IDLE_SECS);
     ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s,
                  "h2_workers: min=%d max=%d, mthrpchild=%d, idle_secs=%d", 
                  minw, maxw, max_threads_per_child, idle_secs);
@@ -172,9 +172,10 @@ static module *h2_conn_mpm_module(void)
     return mpm_module;
 }
 
-apr_status_t h2_conn_setup(h2_ctx *ctx, conn_rec *c, request_rec *r)
+apr_status_t h2_conn_setup(conn_rec *c, request_rec *r, server_rec *s)
 {
     h2_session *session;
+    h2_ctx *ctx;
     apr_status_t status;
     
     if (!workers) {
@@ -183,24 +184,19 @@ apr_status_t h2_conn_setup(h2_ctx *ctx,
         return APR_EGENERAL;
     }
     
-    if (r) {
-        status = h2_session_rcreate(&session, r, ctx, workers);
-    }
-    else {
-        status = h2_session_create(&session, c, ctx, workers);
-    }
-
-    if (status == APR_SUCCESS) {
+    if (APR_SUCCESS == (status = h2_session_create(&session, c, r, s, workers))) {
+        ctx = h2_ctx_get(c, 1);
         h2_ctx_session_set(ctx, session);
     }
+    
     return status;
 }
 
-apr_status_t h2_conn_run(struct h2_ctx *ctx, conn_rec *c)
+apr_status_t h2_conn_run(conn_rec *c)
 {
     apr_status_t status;
     int mpm_state = 0;
-    h2_session *session = h2_ctx_session_get(ctx);
+    h2_session *session = h2_ctx_get_session(c);
     
     ap_assert(session);
     do {
@@ -249,7 +245,7 @@ apr_status_t h2_conn_run(struct h2_ctx *
 
 apr_status_t h2_conn_pre_close(struct h2_ctx *ctx, conn_rec *c)
 {
-    h2_session *session = h2_ctx_session_get(ctx);
+    h2_session *session = h2_ctx_get_session(c);
     if (session) {
         apr_status_t status = h2_session_pre_close(session, async_mpm);
         return (status == APR_SUCCESS)? DONE : status;
@@ -310,8 +306,10 @@ conn_rec *h2_slave_create(conn_rec *mast
     c->filter_conn_ctx        = NULL;
 #endif
     c->bucket_alloc           = apr_bucket_alloc_create(pool);
-    c->data_in_input_filters  = 0;
-    c->data_in_output_filters = 0;
+#if !AP_MODULE_MAGIC_AT_LEAST(20180720, 1)
+     c->data_in_input_filters  = 0;
+     c->data_in_output_filters = 0;
+#endif
     /* prevent mpm_event from making wrong assumptions about this connection,
      * like e.g. using its socket for an async read check. */
     c->clogging_input_filters = 1;

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_conn.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_conn.h?rev=1855431&r1=1855430&r2=1855431&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_conn.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_conn.h Wed Mar 13 15:00:57 2019
@@ -23,21 +23,21 @@ struct h2_task;
 /**
  * Setup the connection and our context for HTTP/2 processing
  *
- * @param ctx the http2 context to setup
  * @param c the connection HTTP/2 is starting on
  * @param r the upgrade request that still awaits an answer, optional
+ * @param s the server selected for this connection (can be != c->base_server)
  */
-apr_status_t h2_conn_setup(struct h2_ctx *ctx, conn_rec *c, request_rec *r);
+apr_status_t h2_conn_setup(conn_rec *c, request_rec *r, server_rec *s);
 
 /**
  * Run the HTTP/2 connection in synchronous fashion. 
  * Return when the HTTP/2 session is done
  * and the connection will close or a fatal error occurred.
  *
- * @param ctx the http2 context to run
+ * @param c the http2 connection to run
  * @return APR_SUCCESS when session is done.
  */
-apr_status_t h2_conn_run(struct h2_ctx *ctx, conn_rec *c);
+apr_status_t h2_conn_run(conn_rec *c);
 
 /**
  * The connection is about to close. If we have not send a GOAWAY

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.c?rev=1855431&r1=1855430&r2=1855431&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.c Wed Mar 13 15:00:57 2019
@@ -40,12 +40,17 @@
  * ~= 1300 bytes */
 #define WRITE_SIZE_INITIAL    1300
 
-/* Calculated like this: max TLS record size 16*1024
- *   - 40 (IP) - 20 (TCP) - 40 (TCP options) 
- *    - TLS overhead (60-100) 
- * which seems to create less TCP packets overall
+/* The maximum we'd like to write in one chunk is
+ * the max size of a TLS record. When pushing
+ * many frames down the h2 connection, this might
+ * align differently because of headers and other
+ * frames or simply as not sufficient data is
+ * in a response body.
+ * However keeping frames at or below this limit
+ * should make optimizations at the layer that writes
+ * to TLS easier.
  */
-#define WRITE_SIZE_MAX        (TLS_DATA_MAX - 100) 
+#define WRITE_SIZE_MAX        (TLS_DATA_MAX) 
 
 
 static void h2_conn_io_bb_log(conn_rec *c, int stream_id, int level, 
@@ -123,21 +128,20 @@ static void h2_conn_io_bb_log(conn_rec *
 
 }
 
-apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, 
-                             const h2_config *cfg)
+apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, server_rec *s)
 {
     io->c              = c;
     io->output         = apr_brigade_create(c->pool, c->bucket_alloc);
     io->is_tls         = h2_h2_is_tls(c);
     io->buffer_output  = io->is_tls;
-    io->flush_threshold = (apr_size_t)h2_config_geti64(cfg, H2_CONF_STREAM_MAX_MEM);
+    io->flush_threshold = (apr_size_t)h2_config_sgeti64(s, H2_CONF_STREAM_MAX_MEM);
 
     if (io->is_tls) {
         /* This is what we start with, 
          * see https://issues.apache.org/jira/browse/TS-2503 
          */
-        io->warmup_size    = h2_config_geti64(cfg, H2_CONF_TLS_WARMUP_SIZE);
-        io->cooldown_usecs = (h2_config_geti(cfg, H2_CONF_TLS_COOLDOWN_SECS) 
+        io->warmup_size    = h2_config_sgeti64(s, H2_CONF_TLS_WARMUP_SIZE);
+        io->cooldown_usecs = (h2_config_sgeti(s, H2_CONF_TLS_COOLDOWN_SECS) 
                               * APR_USEC_PER_SEC);
         io->write_size     = (io->cooldown_usecs > 0? 
                               WRITE_SIZE_INITIAL : WRITE_SIZE_MAX); 

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.h?rev=1855431&r1=1855430&r2=1855431&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_conn_io.h Wed Mar 13 15:00:57 2019
@@ -48,8 +48,7 @@ typedef struct {
     apr_size_t slen;
 } h2_conn_io;
 
-apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, 
-                             const struct h2_config *cfg);
+apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, server_rec *s);
 
 /**
  * Append data to the buffered output.

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.c?rev=1855431&r1=1855430&r2=1855431&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.c Wed Mar 13 15:00:57 2019
@@ -29,8 +29,8 @@ static h2_ctx *h2_ctx_create(const conn_
 {
     h2_ctx *ctx = apr_pcalloc(c->pool, sizeof(h2_ctx));
     ap_assert(ctx);
+    h2_ctx_server_update(ctx, c->base_server);
     ap_set_module_config(c->conn_config, &http2_module, ctx);
-    h2_ctx_server_set(ctx, c->base_server);
     return ctx;
 }
 
@@ -79,8 +79,9 @@ h2_ctx *h2_ctx_protocol_set(h2_ctx *ctx,
     return ctx;
 }
 
-h2_session *h2_ctx_session_get(h2_ctx *ctx)
+h2_session *h2_ctx_get_session(conn_rec *c)
 {
+    h2_ctx *ctx = h2_ctx_get(c, 0);
     return ctx? ctx->session : NULL;
 }
 
@@ -89,33 +90,17 @@ void h2_ctx_session_set(h2_ctx *ctx, str
     ctx->session = session;
 }
 
-server_rec *h2_ctx_server_get(h2_ctx *ctx)
+h2_ctx *h2_ctx_server_update(h2_ctx *ctx, server_rec *s)
 {
-    return ctx? ctx->server : NULL;
-}
-
-h2_ctx *h2_ctx_server_set(h2_ctx *ctx, server_rec *s)
-{
-    ctx->server = s;
+    if (ctx->server != s) {
+        ctx->server = s;
+    }
     return ctx;
 }
 
-int h2_ctx_is_task(h2_ctx *ctx)
-{
-    return ctx && ctx->task;
-}
-
-h2_task *h2_ctx_get_task(h2_ctx *ctx)
+h2_task *h2_ctx_get_task(conn_rec *c)
 {
+    h2_ctx *ctx = h2_ctx_get(c, 0);
     return ctx? ctx->task : NULL;
 }
 
-h2_task *h2_ctx_cget_task(conn_rec *c)
-{
-    return h2_ctx_get_task(h2_ctx_get(c, 0));
-}
-
-h2_task *h2_ctx_rget_task(request_rec *r)
-{
-    return h2_ctx_get_task(h2_ctx_rget(r));
-}

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.h?rev=1855431&r1=1855430&r2=1855431&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_ctx.h Wed Mar 13 15:00:57 2019
@@ -56,12 +56,11 @@ h2_ctx *h2_ctx_create_for(const conn_rec
  */
 h2_ctx *h2_ctx_protocol_set(h2_ctx *ctx, const char *proto);
 
-/* Set the server_rec relevant for this context.
+/* Update the server_rec relevant for this context. A server for
+ * a connection may change during SNI handling, for example.
  */
-h2_ctx *h2_ctx_server_set(h2_ctx *ctx, server_rec *s);
-server_rec *h2_ctx_server_get(h2_ctx *ctx);
+h2_ctx *h2_ctx_server_update(h2_ctx *ctx, server_rec *s);
 
-struct h2_session *h2_ctx_session_get(h2_ctx *ctx);
 void h2_ctx_session_set(h2_ctx *ctx, struct h2_session *session);
 
 /**
@@ -69,10 +68,8 @@ void h2_ctx_session_set(h2_ctx *ctx, str
  */
 const char *h2_ctx_protocol_get(const conn_rec *c);
 
-int h2_ctx_is_task(h2_ctx *ctx);
+struct h2_session *h2_ctx_get_session(conn_rec *c);
+struct h2_task *h2_ctx_get_task(conn_rec *c);
 
-struct h2_task *h2_ctx_get_task(h2_ctx *ctx);
-struct h2_task *h2_ctx_cget_task(conn_rec *c);
-struct h2_task *h2_ctx_rget_task(request_rec *r);
 
 #endif /* defined(__mod_h2__h2_ctx__) */

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_filter.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_filter.c?rev=1855431&r1=1855430&r2=1855431&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_filter.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_filter.c Wed Mar 13 15:00:57 2019
@@ -54,6 +54,7 @@ static apr_status_t recv_RAW_DATA(conn_r
     const char *data;
     ssize_t n;
     
+    (void)c;
     status = apr_bucket_read(b, &data, &len, block);
     
     while (status == APR_SUCCESS && len > 0) {
@@ -71,10 +72,10 @@ static apr_status_t recv_RAW_DATA(conn_r
         }
         else {
             session->io.bytes_read += n;
-            if (len <= n) {
+            if ((apr_ssize_t)len <= n) {
                 break;
             }
-            len -= n;
+            len -= (apr_size_t)n;
             data += n;
         }
     }
@@ -277,6 +278,7 @@ apr_bucket *h2_bucket_observer_beam(stru
                                     apr_bucket_brigade *dest,
                                     const apr_bucket *src)
 {
+    (void)beam;
     if (H2_BUCKET_IS_OBSERVER(src)) {
         h2_bucket_observer *l = (h2_bucket_observer *)src->data; 
         apr_bucket *b = h2_bucket_observer_create(dest->bucket_alloc, 
@@ -311,8 +313,7 @@ static void add_settings(apr_bucket_brig
     bbout(bb, "  \"settings\": {\n");
     bbout(bb, "    \"SETTINGS_MAX_CONCURRENT_STREAMS\": %d,\n", m->max_streams); 
     bbout(bb, "    \"SETTINGS_MAX_FRAME_SIZE\": %d,\n", 16*1024); 
-    bbout(bb, "    \"SETTINGS_INITIAL_WINDOW_SIZE\": %d,\n",
-          h2_config_geti(s->config, H2_CONF_WIN_SIZE));
+    bbout(bb, "    \"SETTINGS_INITIAL_WINDOW_SIZE\": %d,\n", h2_config_sgeti(s->s, H2_CONF_WIN_SIZE));
     bbout(bb, "    \"SETTINGS_ENABLE_PUSH\": %d\n", h2_session_push_enabled(s)); 
     bbout(bb, "  }%s\n", last? "" : ",");
 }
@@ -431,41 +432,38 @@ static void add_stats(apr_bucket_brigade
 
 static apr_status_t h2_status_insert(h2_task *task, apr_bucket *b)
 {
-    conn_rec *c = task->c->master;
-    h2_ctx *h2ctx = h2_ctx_get(c, 0);
-    h2_session *session;
-    h2_stream *stream;
+    h2_mplx *m = task->mplx;
+    h2_stream *stream = h2_mplx_stream_get(m, task->stream_id);
+    h2_session *s;
+    conn_rec *c;
+    
     apr_bucket_brigade *bb;
     apr_bucket *e;
     int32_t connFlowIn, connFlowOut;
     
-    
-    if (!h2ctx || (session = h2_ctx_session_get(h2ctx)) == NULL) {
-        return APR_SUCCESS;
-    }
-    
-    stream = h2_session_stream_get(session, task->stream_id);
     if (!stream) {
         /* stream already done */
         return APR_SUCCESS;
     }
+    s = stream->session;
+    c = s->c;
     
     bb = apr_brigade_create(stream->pool, c->bucket_alloc);
     
-    connFlowIn = nghttp2_session_get_effective_local_window_size(session->ngh2); 
-    connFlowOut = nghttp2_session_get_remote_window_size(session->ngh2);
+    connFlowIn = nghttp2_session_get_effective_local_window_size(s->ngh2); 
+    connFlowOut = nghttp2_session_get_remote_window_size(s->ngh2);
      
     bbout(bb, "{\n");
     bbout(bb, "  \"version\": \"draft-01\",\n");
-    add_settings(bb, session, 0);
-    add_peer_settings(bb, session, 0);
+    add_settings(bb, s, 0);
+    add_peer_settings(bb, s, 0);
     bbout(bb, "  \"connFlowIn\": %d,\n", connFlowIn);
     bbout(bb, "  \"connFlowOut\": %d,\n", connFlowOut);
-    bbout(bb, "  \"sentGoAway\": %d,\n", session->local.shutdown);
+    bbout(bb, "  \"sentGoAway\": %d,\n", s->local.shutdown);
 
-    add_streams(bb, session, 0);
+    add_streams(bb, s, 0);
     
-    add_stats(bb, session, stream, 1);
+    add_stats(bb, s, stream, 1);
     bbout(bb, "}\n");
     
     while ((e = APR_BRIGADE_FIRST(bb)) != APR_BRIGADE_SENTINEL(bb)) {
@@ -497,7 +495,6 @@ static apr_status_t status_event(void *c
 
 int h2_filter_h2_status_handler(request_rec *r)
 {
-    h2_ctx *ctx = h2_ctx_rget(r);
     conn_rec *c = r->connection;
     h2_task *task;
     apr_bucket_brigade *bb;
@@ -511,7 +508,7 @@ int h2_filter_h2_status_handler(request_
         return DECLINED;
     }
 
-    task = ctx? h2_ctx_get_task(ctx) : NULL;
+    task = h2_ctx_get_task(r->connection);
     if (task) {
 
         if ((status = ap_discard_request_body(r)) != OK) {

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_from_h1.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_from_h1.c?rev=1855431&r1=1855430&r2=1855431&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_from_h1.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_from_h1.c Wed Mar 13 15:00:57 2019
@@ -594,18 +594,20 @@ apr_status_t h2_filter_headers_out(ap_fi
         }
     }
     
-    if (r->header_only) {
+    if (r->header_only || AP_STATUS_IS_HEADER_ONLY(r->status)) {
         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
-                      "h2_task(%s): header_only, cleanup output brigade", 
+                      "h2_task(%s): headers only, cleanup output brigade", 
                       task->id);
         b = body_bucket? body_bucket : APR_BRIGADE_FIRST(bb);
         while (b != APR_BRIGADE_SENTINEL(bb)) {
             next = APR_BUCKET_NEXT(b);
             if (APR_BUCKET_IS_EOS(b) || AP_BUCKET_IS_EOR(b)) {
                 break;
-            } 
-            APR_BUCKET_REMOVE(b);
-            apr_bucket_destroy(b);
+            }
+            if (!H2_BUCKET_IS_HEADERS(b)) {
+                APR_BUCKET_REMOVE(b);
+                apr_bucket_destroy(b);
+            }
             b = next;
         }
     }

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_h2.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_h2.c?rev=1855431&r1=1855430&r2=1855431&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_h2.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_h2.c Wed Mar 13 15:00:57 2019
@@ -463,19 +463,18 @@ int h2_h2_is_tls(conn_rec *c)
     return opt_ssl_is_https && opt_ssl_is_https(c);
 }
 
-int h2_is_acceptable_connection(conn_rec *c, int require_all) 
+int h2_is_acceptable_connection(conn_rec *c, request_rec *r, int require_all) 
 {
     int is_tls = h2_h2_is_tls(c);
-    const h2_config *cfg = h2_config_get(c);
 
-    if (is_tls && h2_config_geti(cfg, H2_CONF_MODERN_TLS_ONLY) > 0) {
+    if (is_tls && h2_config_cgeti(c, H2_CONF_MODERN_TLS_ONLY) > 0) {
         /* Check TLS connection for modern TLS parameters, as defined in
          * RFC 7540 and https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
          */
         apr_pool_t *pool = c->pool;
         server_rec *s = c->base_server;
         char *val;
-        
+
         if (!opt_ssl_var_lookup) {
             /* unable to check */
             return 0;
@@ -521,26 +520,22 @@ int h2_is_acceptable_connection(conn_rec
     return 1;
 }
 
-int h2_allows_h2_direct(conn_rec *c)
+static int h2_allows_h2_direct(conn_rec *c)
 {
-    const h2_config *cfg = h2_config_get(c);
     int is_tls = h2_h2_is_tls(c);
     const char *needed_protocol = is_tls? "h2" : "h2c";
-    int h2_direct = h2_config_geti(cfg, H2_CONF_DIRECT);
+    int h2_direct = h2_config_cgeti(c, H2_CONF_DIRECT);
     
     if (h2_direct < 0) {
         h2_direct = is_tls? 0 : 1;
     }
-    return (h2_direct 
-            && ap_is_allowed_protocol(c, NULL, NULL, needed_protocol));
+    return (h2_direct && ap_is_allowed_protocol(c, NULL, NULL, needed_protocol));
 }
 
-int h2_allows_h2_upgrade(conn_rec *c)
+int h2_allows_h2_upgrade(request_rec *r)
 {
-    const h2_config *cfg = h2_config_get(c);
-    int h2_upgrade = h2_config_geti(cfg, H2_CONF_UPGRADE);
-    
-    return h2_upgrade > 0 || (h2_upgrade < 0 && !h2_h2_is_tls(c));
+    int h2_upgrade = h2_config_rgeti(r, H2_CONF_UPGRADE);
+    return h2_upgrade > 0 || (h2_upgrade < 0 && !h2_h2_is_tls(r->connection));
 }
 
 /*******************************************************************************
@@ -581,14 +576,17 @@ int h2_h2_process_conn(conn_rec* c)
 {
     apr_status_t status;
     h2_ctx *ctx;
+    server_rec *s;
     
     if (c->master) {
         return DECLINED;
     }
     
     ctx = h2_ctx_get(c, 0);
+    s = ctx? ctx->server : c->base_server;
+    
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, process_conn");
-    if (h2_ctx_is_task(ctx)) {
+    if (ctx && ctx->task) {
         /* our stream pseudo connection */
         ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, task, declined");
         return DECLINED;
@@ -601,19 +599,19 @@ int h2_h2_process_conn(conn_rec* c)
             ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, process_conn, "
                           "new connection using protocol '%s', direct=%d, "
                           "tls acceptable=%d", proto, h2_allows_h2_direct(c), 
-                          h2_is_acceptable_connection(c, 1));
+                          h2_is_acceptable_connection(c, NULL, 1));
         }
         
         if (!strcmp(AP_PROTOCOL_HTTP1, proto)
             && h2_allows_h2_direct(c) 
-            && h2_is_acceptable_connection(c, 1)) {
+            && h2_is_acceptable_connection(c, NULL, 1)) {
             /* Fresh connection still is on http/1.1 and H2Direct is enabled. 
              * Otherwise connection is in a fully acceptable state.
              * -> peek at the first 24 incoming bytes
              */
             apr_bucket_brigade *temp;
-            char *s = NULL;
-            apr_size_t slen;
+            char *peek = NULL;
+            apr_size_t peeklen;
             
             temp = apr_brigade_create(c->pool, c->bucket_alloc);
             status = ap_get_brigade(c->input_filters, temp,
@@ -626,8 +624,8 @@ int h2_h2_process_conn(conn_rec* c)
                 return DECLINED;
             }
             
-            apr_brigade_pflatten(temp, &s, &slen, c->pool);
-            if ((slen >= 24) && !memcmp(H2_MAGIC_TOKEN, s, 24)) {
+            apr_brigade_pflatten(temp, &peek, &peeklen, c->pool);
+            if ((peeklen >= 24) && !memcmp(H2_MAGIC_TOKEN, peek, 24)) {
                 ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
                               "h2_h2, direct mode detected");
                 if (!ctx) {
@@ -638,7 +636,7 @@ int h2_h2_process_conn(conn_rec* c)
             else if (APLOGctrace2(c)) {
                 ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
                               "h2_h2, not detected in %d bytes(base64): %s", 
-                              (int)slen, h2_util_base64url_encode(s, slen, c->pool));
+                              (int)peeklen, h2_util_base64url_encode(peek, peeklen, c->pool));
             }
             
             apr_brigade_destroy(temp);
@@ -647,15 +645,16 @@ int h2_h2_process_conn(conn_rec* c)
 
     if (ctx) {
         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "process_conn");
-        if (!h2_ctx_session_get(ctx)) {
-            status = h2_conn_setup(ctx, c, NULL);
+        
+        if (!h2_ctx_get_session(c)) {
+            status = h2_conn_setup(c, NULL, s);
             ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, c, "conn_setup");
             if (status != APR_SUCCESS) {
                 h2_ctx_clear(c);
                 return !OK;
             }
         }
-        h2_conn_run(ctx, c);
+        h2_conn_run(c);
         return OK;
     }
     
@@ -684,16 +683,17 @@ static int h2_h2_pre_close_conn(conn_rec
 
 static void check_push(request_rec *r, const char *tag)
 {
-    const h2_config *conf = h2_config_rget(r);
-    if (!r->expecting_100 
-        && conf && conf->push_list && conf->push_list->nelts > 0) {
+    apr_array_header_t *push_list = h2_config_push_list(r);
+
+    if (!r->expecting_100 && push_list && push_list->nelts > 0) {
         int i, old_status;
         const char *old_line;
+        
         ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, 
                       "%s, early announcing %d resources for push",
-                      tag, conf->push_list->nelts);
-        for (i = 0; i < conf->push_list->nelts; ++i) {
-            h2_push_res *push = &APR_ARRAY_IDX(conf->push_list, i, h2_push_res);
+                      tag, push_list->nelts);
+        for (i = 0; i < push_list->nelts; ++i) {
+            h2_push_res *push = &APR_ARRAY_IDX(push_list, i, h2_push_res);
             apr_table_add(r->headers_out, "Link", 
                            apr_psprintf(r->pool, "<%s>; rel=preload%s", 
                                         push->uri_ref, push->critical? "; critical" : ""));
@@ -712,8 +712,7 @@ static int h2_h2_post_read_req(request_r
 {
     /* slave connection? */
     if (r->connection->master) {
-        h2_ctx *ctx = h2_ctx_rget(r);
-        struct h2_task *task = h2_ctx_get_task(ctx);
+        struct h2_task *task = h2_ctx_get_task(r->connection);
         /* This hook will get called twice on internal redirects. Take care
          * that we manipulate filters only once. */
         if (task && !task->filters_set) {
@@ -746,12 +745,10 @@ static int h2_h2_late_fixups(request_rec
 {
     /* slave connection? */
     if (r->connection->master) {
-        h2_ctx *ctx = h2_ctx_rget(r);
-        struct h2_task *task = h2_ctx_get_task(ctx);
+        struct h2_task *task = h2_ctx_get_task(r->connection);
         if (task) {
             /* check if we copy vs. setaside files in this location */
-            task->output.copy_files = h2_config_geti(h2_config_rget(r), 
-                                                     H2_CONF_COPY_FILES);
+            task->output.copy_files = h2_config_rgeti(r, H2_CONF_COPY_FILES);
             if (task->output.copy_files) {
                 ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, task->c,
                               "h2_slave_out(%s): copy_files on", task->id);

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_h2.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_h2.h?rev=1855431&r1=1855430&r2=1855431&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_h2.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_h2.h Wed Mar 13 15:00:57 2019
@@ -57,23 +57,15 @@ void h2_h2_register_hooks(void);
  *    the handshake is still ongoing.
  * @return != 0 iff connection requirements are met
  */
-int h2_is_acceptable_connection(conn_rec *c, int require_all);
-
-/**
- * Check if the "direct" HTTP/2 mode of protocol handling is enabled
- * for the given connection.
- * @param c the connection to check
- * @return != 0 iff direct mode is enabled
- */
-int h2_allows_h2_direct(conn_rec *c);
+int h2_is_acceptable_connection(conn_rec *c, request_rec *r, int require_all);
 
 /**
  * Check if the "Upgrade" HTTP/1.1 mode of protocol switching is enabled
- * for the given connection.
- * @param c the connection to check
+ * for the given request.
+ * @param r the request to check
  * @return != 0 iff Upgrade switching is enabled
  */
-int h2_allows_h2_upgrade(conn_rec *c);
+int h2_allows_h2_upgrade(request_rec *r);
 
 
 #endif /* defined(__mod_h2__h2_h2__) */

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_headers.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_headers.c?rev=1855431&r1=1855430&r2=1855431&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_headers.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_headers.c Wed Mar 13 15:00:57 2019
@@ -28,6 +28,7 @@
 
 #include "h2_private.h"
 #include "h2_h2.h"
+#include "h2_config.h"
 #include "h2_util.h"
 #include "h2_request.h"
 #include "h2_headers.h"
@@ -128,21 +129,27 @@ h2_headers *h2_headers_rcreate(request_r
 {
     h2_headers *headers = h2_headers_create(status, header, r->notes, 0, pool);
     if (headers->status == HTTP_FORBIDDEN) {
-        const char *cause = apr_table_get(r->notes, "ssl-renegotiate-forbidden");
-        if (cause) {
-            /* This request triggered a TLS renegotiation that is now allowed 
-             * in HTTP/2. Tell the client that it should use HTTP/1.1 for this.
-             */
-            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, headers->status, r,
-                          APLOGNO(03061) 
-                          "h2_headers(%ld): renegotiate forbidden, cause: %s",
-                          (long)r->connection->id, cause);
-            headers->status = H2_ERR_HTTP_1_1_REQUIRED;
+        request_rec *r_prev;
+        for (r_prev = r; r_prev != NULL; r_prev = r_prev->prev) {
+            const char *cause = apr_table_get(r_prev->notes, "ssl-renegotiate-forbidden");
+            if (cause) {
+                /* This request triggered a TLS renegotiation that is not allowed
+                 * in HTTP/2. Tell the client that it should use HTTP/1.1 for this.
+                 */
+                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, headers->status, r,
+                              APLOGNO(03061)
+                              "h2_headers(%ld): renegotiate forbidden, cause: %s",
+                              (long)r->connection->id, cause);
+                headers->status = H2_ERR_HTTP_1_1_REQUIRED;
+                break;
+            }
         }
     }
     if (is_unsafe(r->server)) {
-        apr_table_setn(headers->notes, H2_HDR_CONFORMANCE, 
-                       H2_HDR_CONFORMANCE_UNSAFE);
+        apr_table_setn(headers->notes, H2_HDR_CONFORMANCE, H2_HDR_CONFORMANCE_UNSAFE);
+    }
+    if (h2_config_rgeti(r, H2_CONF_PUSH) == 0 && h2_config_sgeti(r->server, H2_CONF_PUSH) != 0) {
+        apr_table_setn(headers->notes, H2_PUSH_MODE_NOTE, "0");
     }
     return headers;
 }