Index: httpd-2.4.23/modules/http2/config2.m4
===================================================================
--- httpd-2.4.23.orig/modules/http2/config2.m4	2019-04-02 13:39:34.060792511 +0200
+++ httpd-2.4.23/modules/http2/config2.m4	2019-04-02 13:39:34.256793490 +0200
@@ -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
Index: httpd-2.4.23/modules/http2/h2_alt_svc.c
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_alt_svc.c	2019-04-02 13:39:34.064792531 +0200
+++ httpd-2.4.23/modules/http2/h2_alt_svc.c	2019-04-02 13:39:34.256793490 +0200
@@ -74,7 +74,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) {
@@ -86,8 +86,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
@@ -98,7 +98,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);
             }
@@ -106,8 +106,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;
Index: httpd-2.4.23/modules/http2/h2_config.c
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_config.c	2019-04-02 13:39:34.192793170 +0200
+++ httpd-2.4.23/modules/http2/h2_config.c	2019-04-02 13:42:32.649683136 +0200
@@ -41,6 +41,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 */
@@ -63,6 +112,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)
@@ -70,12 +131,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;
@@ -97,19 +156,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;
@@ -148,25 +199,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:
@@ -190,7 +268,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:
@@ -203,12 +282,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);
@@ -216,9 +376,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);
@@ -227,166 +540,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";
 }
 
@@ -446,100 +749,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;
 }
@@ -548,8 +839,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;
     
@@ -574,42 +863,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) {
@@ -651,7 +952,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,
@@ -661,7 +962,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,
@@ -669,33 +970,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);
-}
Index: httpd-2.4.23/modules/http2/h2_config.h
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_config.h	2019-04-02 13:39:34.192793170 +0200
+++ httpd-2.4.23/modules/http2/h2_config.h	2019-04-02 13:42:32.649683136 +0200
@@ -41,6 +41,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;
@@ -52,33 +54,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);
@@ -87,19 +62,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__ */
 
Index: httpd-2.4.23/modules/http2/h2_conn.c
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_conn.c	2019-04-02 13:39:34.220793310 +0200
+++ httpd-2.4.23/modules/http2/h2_conn.c	2019-04-02 13:42:32.649683136 +0200
@@ -17,6 +17,7 @@
 #include <apr_strings.h>
 
 #include <ap_mpm.h>
+#include <ap_mmn.h>
 
 #include <httpd.h>
 #include <http_core.h>
@@ -108,7 +109,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;
@@ -128,7 +128,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);
@@ -171,9 +171,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) {
@@ -182,24 +183,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 {
@@ -248,7 +244,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;
@@ -304,9 +300,15 @@ conn_rec *h2_slave_create(conn_rec *mast
     c->notes                  = apr_table_make(pool, 5);
     c->input_filters          = NULL;
     c->output_filters         = NULL;
+    c->keepalives             = 0;
+#if AP_MODULE_MAGIC_AT_LEAST(20180903, 1)
+    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;
@@ -331,16 +333,15 @@ conn_rec *h2_slave_create(conn_rec *mast
         ap_set_module_config(c->conn_config, mpm, cfg);
     }
 
-    ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, 
-                  "h2_stream(%ld-%d): created slave", master->id, slave_id);
+    ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, c,
+                  "h2_slave(%s): created", c->log_id);
     return c;
 }
 
 void h2_slave_destroy(conn_rec *slave)
 {
-    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, slave,
-                  "h2_stream(%s): destroy slave", 
-                  apr_table_get(slave->notes, H2_TASK_ID_NOTE));
+    ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, slave,
+                  "h2_slave(%s): destroy", slave->log_id);
     slave->sbh = NULL;
     apr_pool_destroy(slave->pool);
 }
@@ -364,6 +365,7 @@ apr_status_t h2_slave_run_pre_connection
         slave->keepalive = AP_CONN_CLOSE;
         return ap_run_pre_connection(slave, csd);
     }
+    ap_assert(slave->output_filters);
     return APR_SUCCESS;
 }
 
Index: httpd-2.4.23/modules/http2/h2_conn.h
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_conn.h	2019-04-02 13:39:34.068792551 +0200
+++ httpd-2.4.23/modules/http2/h2_conn.h	2019-04-02 13:39:34.256793490 +0200
@@ -22,21 +22,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
Index: httpd-2.4.23/modules/http2/h2_conn_io.c
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_conn_io.c	2019-04-02 13:39:34.068792551 +0200
+++ httpd-2.4.23/modules/http2/h2_conn_io.c	2019-04-02 13:42:32.649683136 +0200
@@ -39,12 +39,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, 
@@ -122,21 +127,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); 
Index: httpd-2.4.23/modules/http2/h2_conn_io.h
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_conn_io.h	2019-04-02 13:39:34.068792551 +0200
+++ httpd-2.4.23/modules/http2/h2_conn_io.h	2019-04-02 13:39:34.256793490 +0200
@@ -47,8 +47,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.
Index: httpd-2.4.23/modules/http2/h2_ctx.c
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_ctx.c	2019-04-02 13:39:34.068792551 +0200
+++ httpd-2.4.23/modules/http2/h2_ctx.c	2019-04-02 13:39:34.256793490 +0200
@@ -28,8 +28,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;
 }
 
@@ -78,8 +78,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;
 }
 
@@ -88,33 +89,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));
-}
Index: httpd-2.4.23/modules/http2/h2_ctx.h
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_ctx.h	2016-03-02 12:21:28.000000000 +0100
+++ httpd-2.4.23/modules/http2/h2_ctx.h	2019-04-02 13:39:34.256793490 +0200
@@ -55,12 +55,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);
 
 /**
@@ -68,10 +67,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__) */
Index: httpd-2.4.23/modules/http2/h2_filter.c
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_filter.c	2019-04-02 13:39:34.192793170 +0200
+++ httpd-2.4.23/modules/http2/h2_filter.c	2019-04-02 13:42:32.649683136 +0200
@@ -53,6 +53,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) {
@@ -70,10 +71,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;
         }
     }
@@ -276,6 +277,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, 
@@ -310,8 +312,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? "" : ",");
 }
@@ -430,41 +431,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)) {
@@ -496,7 +494,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;
@@ -510,7 +507,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) {
Index: httpd-2.4.23/modules/http2/h2_from_h1.c
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_from_h1.c	2019-04-02 13:39:34.244793430 +0200
+++ httpd-2.4.23/modules/http2/h2_from_h1.c	2019-04-02 13:39:34.256793490 +0200
@@ -21,8 +21,6 @@
 #include <apr_strings.h>
 
 #include <httpd.h>
-#define AP_STATUS_IS_HEADER_ONLY(x) ((x) == HTTP_NO_CONTENT || \
-                                     (x) == HTTP_NOT_MODIFIED)
 #include <http_core.h>
 #include <http_log.h>
 #include <http_connection.h>
Index: httpd-2.4.23/modules/http2/h2.h
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2.h	2019-04-02 13:39:34.192793170 +0200
+++ httpd-2.4.23/modules/http2/h2.h	2019-04-02 13:42:32.649683136 +0200
@@ -47,12 +47,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 */
@@ -161,5 +161,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__) */
Index: httpd-2.4.23/modules/http2/h2_h2.c
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_h2.c	2019-04-02 13:39:34.220793310 +0200
+++ httpd-2.4.23/modules/http2/h2_h2.c	2019-04-02 13:42:32.649683136 +0200
@@ -462,19 +462,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;
@@ -520,26 +519,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));
 }
 
 /*******************************************************************************
@@ -580,14 +575,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;
@@ -600,19 +598,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,
@@ -625,8 +623,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) {
@@ -637,7 +635,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);
@@ -646,15 +644,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;
     }
     
@@ -683,16 +682,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" : ""));
@@ -711,8 +711,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) {
@@ -745,12 +744,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);
Index: httpd-2.4.23/modules/http2/h2_h2.h
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_h2.h	2019-04-02 13:39:34.072792571 +0200
+++ httpd-2.4.23/modules/http2/h2_h2.h	2019-04-02 13:39:34.260793510 +0200
@@ -56,23 +56,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__) */
Index: httpd-2.4.23/modules/http2/h2_headers.c
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_headers.c	2019-04-02 13:39:34.220793310 +0200
+++ httpd-2.4.23/modules/http2/h2_headers.c	2019-04-02 13:39:34.260793510 +0200
@@ -27,6 +27,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"
@@ -127,21 +128,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;
 }
Index: httpd-2.4.23/modules/http2/h2_mplx.c
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_mplx.c	2019-04-02 13:39:34.220793310 +0200
+++ httpd-2.4.23/modules/http2/h2_mplx.c	2019-04-02 13:42:32.649683136 +0200
@@ -39,7 +39,6 @@
 #include "h2_ctx.h"
 #include "h2_h2.h"
 #include "h2_mplx.h"
-#include "h2_ngn_shed.h"
 #include "h2_request.h"
 #include "h2_stream.h"
 #include "h2_session.h"
@@ -82,12 +81,6 @@ static void check_data_for(h2_mplx *m, h
 static void stream_output_consumed(void *ctx, 
                                    h2_bucket_beam *beam, apr_off_t length)
 {
-    h2_stream *stream = ctx;
-    h2_task *task = stream->task;
-    
-    if (length > 0 && task && task->assigned) {
-        h2_req_engine_out_consumed(task->assigned, task->c, length); 
-    }
 }
 
 static void stream_input_ev(void *ctx, h2_bucket_beam *beam)
@@ -135,7 +128,6 @@ static void stream_cleanup(h2_mplx *m, h
     }
     else if (stream->task) {
         stream->task->c->aborted = 1;
-        apr_thread_cond_broadcast(m->task_thawed);
     }
 }
 
@@ -150,25 +142,19 @@ static void stream_cleanup(h2_mplx *m, h
  *   their HTTP/1 cousins, the separate allocator seems to work better
  *   than protecting a shared h2_session one with an own lock.
  */
-h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *parent, 
-                        const h2_config *conf, 
+h2_mplx *h2_mplx_create(conn_rec *c, server_rec *s, apr_pool_t *parent,
                         h2_workers *workers)
 {
     apr_status_t status = APR_SUCCESS;
     apr_allocator_t *allocator;
     apr_thread_mutex_t *mutex;
     h2_mplx *m;
-    h2_ctx *ctx = h2_ctx_get(c, 0);
-    ap_assert(conf);
     
     m = apr_pcalloc(parent, sizeof(h2_mplx));
     if (m) {
         m->id = c->id;
         m->c = c;
-        m->s = (ctx? h2_ctx_server_get(ctx) : NULL);
-        if (!m->s) {
-            m->s = c->base_server;
-        }
+        m->s = s;
         
         /* We create a pool with its own allocator to be used for
          * processing slave connections. This is the only way to have the
@@ -203,14 +189,8 @@ h2_mplx *h2_mplx_create(conn_rec *c, apr
             return NULL;
         }
         
-        status = apr_thread_cond_create(&m->task_thawed, m->pool);
-        if (status != APR_SUCCESS) {
-            apr_pool_destroy(m->pool);
-            return NULL;
-        }
-    
-        m->max_streams = h2_config_geti(conf, H2_CONF_MAX_STREAMS);
-        m->stream_max_mem = h2_config_geti(conf, H2_CONF_STREAM_MAX_MEM);
+        m->max_streams = h2_config_sgeti(s, H2_CONF_MAX_STREAMS);
+        m->stream_max_mem = h2_config_sgeti(s, H2_CONF_STREAM_MAX_MEM);
 
         m->streams = h2_ihash_create(m->pool, offsetof(h2_stream,id));
         m->sredo = h2_ihash_create(m->pool, offsetof(h2_stream,id));
@@ -231,10 +211,6 @@ h2_mplx *h2_mplx_create(conn_rec *c, apr
         m->limit_change_interval = apr_time_from_msec(100);
         
         m->spare_slaves = apr_array_make(m->pool, 10, sizeof(conn_rec*));
-        
-        m->ngn_shed = h2_ngn_shed_create(m->pool, m->c, m->max_streams, 
-                                         m->stream_max_mem);
-        h2_ngn_shed_set_ctx(m->ngn_shed , m);
     }
     return m;
 }
@@ -326,7 +302,8 @@ static int stream_destroy_iter(void *ctx
                                && !task->rst_error);
             }
             
-            if (reuse_slave && slave->keepalive == AP_CONN_KEEPALIVE) {
+            task->c = NULL;
+            if (reuse_slave) {
                 h2_beam_log(task->output.beam, m->c, APLOG_DEBUG, 
                             APLOGNO(03385) "h2_task_destroy, reuse slave");    
                 h2_task_destroy(task);
@@ -392,10 +369,10 @@ static int report_stream_iter(void *ctx,
     if (task) {
         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c, /* NO APLOGNO */
                       H2_STRM_MSG(stream, "->03198: %s %s %s"
-                      "[started=%d/done=%d/frozen=%d]"), 
+                      "[started=%d/done=%d]"),
                       task->request->method, task->request->authority, 
                       task->request->path, task->worker_started, 
-                      task->worker_done, task->frozen);
+                      task->worker_done);
     }
     else {
         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c, /* NO APLOGNO */
@@ -434,8 +411,10 @@ static int stream_cancel_iter(void *ctx,
 void h2_mplx_release_and_join(h2_mplx *m, apr_thread_cond_t *wait)
 {
     apr_status_t status;
-    int i, wait_secs = 60;
+    int i, wait_secs = 60, old_aborted;
 
+    ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
+                  "h2_mplx(%ld): start release", m->id);
     /* How to shut down a h2 connection:
      * 0. abort and tell the workers that no more tasks will come from us */
     m->aborted = 1;
@@ -443,15 +422,19 @@ void h2_mplx_release_and_join(h2_mplx *m
     
     H2_MPLX_ENTER_ALWAYS(m);
 
+    /* While really terminating any slave connections, treat the master
+     * connection as aborted. It's not as if we could send any more data
+     * at this point. */
+    old_aborted = m->c->aborted;
+    m->c->aborted = 1;
+
     /* How to shut down a h2 connection:
      * 1. cancel all streams still active */
     while (!h2_ihash_iter(m->streams, stream_cancel_iter, m)) {
         /* until empty */
     }
     
-    /* 2. terminate ngn_shed, no more streams
-     * should be scheduled or in the active set */
-    h2_ngn_shed_abort(m->ngn_shed);
+    /* 2. no more streams should be scheduled or in the active set */
     ap_assert(h2_ihash_empty(m->streams));
     ap_assert(h2_iq_empty(m->q));
     
@@ -475,10 +458,6 @@ void h2_mplx_release_and_join(h2_mplx *m
     ap_assert(m->tasks_active == 0);
     m->join_wait = NULL;
     
-    /* 4. close the h2_req_enginge shed */
-    h2_ngn_shed_destroy(m->ngn_shed);
-    m->ngn_shed = NULL;
-    
     /* 4. With all workers done, all streams should be in spurge */
     if (!h2_ihash_empty(m->shold)) {
         ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c, APLOGNO(03516)
@@ -487,6 +466,7 @@ void h2_mplx_release_and_join(h2_mplx *m
         h2_ihash_iter(m->shold, unexpected_stream_iter, m);
     }
     
+    m->c->aborted = old_aborted;
     H2_MPLX_LEAVE(m);
 
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
@@ -783,47 +763,14 @@ apr_status_t h2_mplx_pop_task(h2_mplx *m
     return rv;
 }
 
-static void task_done(h2_mplx *m, h2_task *task, h2_req_engine *ngn)
+static void task_done(h2_mplx *m, h2_task *task)
 {
     h2_stream *stream;
     
-    if (task->frozen) {
-        /* this task was handed over to an engine for processing 
-         * and the original worker has finished. That means the 
-         * engine may start processing now. */
-        h2_task_thaw(task);
-        apr_thread_cond_broadcast(m->task_thawed);
-        return;
-    }
-        
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
                   "h2_mplx(%ld): task(%s) done", m->id, task->id);
     out_close(m, task);
     
-    if (ngn) {
-        apr_off_t bytes = 0;
-        h2_beam_send(task->output.beam, NULL, APR_NONBLOCK_READ);
-        bytes += h2_beam_get_buffered(task->output.beam);
-        if (bytes > 0) {
-            /* we need to report consumed and current buffered output
-             * to the engine. The request will be streamed out or cancelled,
-             * no more data is coming from it and the engine should update
-             * its calculations before we destroy this information. */
-            h2_req_engine_out_consumed(ngn, task->c, bytes);
-        }
-    }
-    
-    if (task->engine) {
-        if (!m->aborted && !task->c->aborted 
-            && !h2_req_engine_is_shutdown(task->engine)) {
-            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c, APLOGNO(10022)
-                          "h2_mplx(%ld): task(%s) has not-shutdown "
-                          "engine(%s)", m->id, task->id, 
-                          h2_req_engine_get_id(task->engine));
-        }
-        h2_ngn_shed_done_ngn(m->ngn_shed, task->engine);
-    }
-    
     task->worker_done = 1;
     task->done_at = apr_time_now();
     ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
@@ -845,18 +792,24 @@ static void task_done(h2_mplx *m, h2_tas
                           m->id, m->limit_active);
         }
     }
-    
+
+    ap_assert(task->done_done == 0);
+
     stream = h2_ihash_get(m->streams, task->stream_id);
     if (stream) {
         /* stream not done yet. */
         if (!m->aborted && h2_ihash_get(m->sredo, stream->id)) {
             /* reset and schedule again */
+            task->worker_done = 0;
             h2_task_redo(task);
             h2_ihash_remove(m->sredo, stream->id);
             h2_iq_add(m->q, stream->id, NULL, NULL);
+            ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, m->c,
+                          H2_STRM_MSG(stream, "redo, added to q"));
         }
         else {
             /* stream not cleaned up, stay around */
+            task->done_done = 1;
             ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
                           H2_STRM_MSG(stream, "task_done, stream open")); 
             if (stream->input) {
@@ -869,6 +822,7 @@ static void task_done(h2_mplx *m, h2_tas
     }
     else if ((stream = h2_ihash_get(m->shold, task->stream_id)) != NULL) {
         /* stream is done, was just waiting for this. */
+        task->done_done = 1;
         ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
                       H2_STRM_MSG(stream, "task_done, in hold"));
         if (stream->input) {
@@ -893,7 +847,7 @@ void h2_mplx_task_done(h2_mplx *m, h2_ta
 {
     H2_MPLX_ENTER_ALWAYS(m);
 
-    task_done(m, task, NULL);
+    task_done(m, task);
     --m->tasks_active;
     
     if (m->join_wait) {
@@ -976,6 +930,9 @@ static apr_status_t unschedule_slow_task
      */
     n = (m->tasks_active - m->limit_active - (int)h2_ihash_count(m->sredo));
     while (n > 0 && (stream = get_latest_repeatable_unsubmitted_stream(m))) {
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
+                      "h2_mplx(%s): unschedule, resetting task for redo later",
+                      stream->task->id);
         h2_task_rst(stream->task, H2_ERR_CANCEL);
         h2_ihash_add(m->sredo, stream);
         --n;
@@ -1084,142 +1041,6 @@ apr_status_t h2_mplx_idle(h2_mplx *m)
 }
 
 /*******************************************************************************
- * HTTP/2 request engines
- ******************************************************************************/
-
-typedef struct {
-    h2_mplx * m;
-    h2_req_engine *ngn;
-    int streams_updated;
-} ngn_update_ctx;
-
-static int ngn_update_window(void *ctx, void *val)
-{
-    ngn_update_ctx *uctx = ctx;
-    h2_stream *stream = val;
-    if (stream->task && stream->task->assigned == uctx->ngn
-        && output_consumed_signal(uctx->m, stream->task)) {
-        ++uctx->streams_updated;
-    }
-    return 1;
-}
-
-static apr_status_t ngn_out_update_windows(h2_mplx *m, h2_req_engine *ngn)
-{
-    ngn_update_ctx ctx;
-        
-    ctx.m = m;
-    ctx.ngn = ngn;
-    ctx.streams_updated = 0;
-    h2_ihash_iter(m->streams, ngn_update_window, &ctx);
-    
-    return ctx.streams_updated? APR_SUCCESS : APR_EAGAIN;
-}
-
-apr_status_t h2_mplx_req_engine_push(const char *ngn_type, 
-                                     request_rec *r,
-                                     http2_req_engine_init *einit)
-{
-    apr_status_t status;
-    h2_mplx *m;
-    h2_task *task;
-    h2_stream *stream;
-    
-    task = h2_ctx_rget_task(r);
-    if (!task) {
-        return APR_ECONNABORTED;
-    }
-    m = task->mplx;
-    
-    H2_MPLX_ENTER(m);
-
-    stream = h2_ihash_get(m->streams, task->stream_id);
-    if (stream) {
-        status = h2_ngn_shed_push_request(m->ngn_shed, ngn_type, r, einit);
-    }
-    else {
-        status = APR_ECONNABORTED;
-    }
-
-    H2_MPLX_LEAVE(m);
-    return status;
-}
-
-apr_status_t h2_mplx_req_engine_pull(h2_req_engine *ngn, 
-                                     apr_read_type_e block, 
-                                     int capacity, 
-                                     request_rec **pr)
-{   
-    h2_ngn_shed *shed = h2_ngn_shed_get_shed(ngn);
-    h2_mplx *m = h2_ngn_shed_get_ctx(shed);
-    apr_status_t status;
-    int want_shutdown;
-    
-    H2_MPLX_ENTER(m);
-
-    want_shutdown = (block == APR_BLOCK_READ);
-
-    /* Take this opportunity to update output consummation 
-     * for this engine */
-    ngn_out_update_windows(m, ngn);
-    
-    if (want_shutdown && !h2_iq_empty(m->q)) {
-        /* For a blocking read, check first if requests are to be
-         * had and, if not, wait a short while before doing the
-         * blocking, and if unsuccessful, terminating read.
-         */
-        status = h2_ngn_shed_pull_request(shed, ngn, capacity, 1, pr);
-        if (APR_STATUS_IS_EAGAIN(status)) {
-            ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
-                          "h2_mplx(%ld): start block engine pull", m->id);
-            apr_thread_cond_timedwait(m->task_thawed, m->lock, 
-                                      apr_time_from_msec(20));
-            status = h2_ngn_shed_pull_request(shed, ngn, capacity, 1, pr);
-        }
-    }
-    else {
-        status = h2_ngn_shed_pull_request(shed, ngn, capacity,
-                                          want_shutdown, pr);
-    }
-
-    H2_MPLX_LEAVE(m);
-    return status;
-}
- 
-void h2_mplx_req_engine_done(h2_req_engine *ngn, conn_rec *r_conn,
-                             apr_status_t status)
-{
-    h2_task *task = h2_ctx_cget_task(r_conn);
-    
-    if (task) {
-        h2_mplx *m = task->mplx;
-        h2_stream *stream;
-
-        H2_MPLX_ENTER_ALWAYS(m);
-
-        stream = h2_ihash_get(m->streams, task->stream_id);
-        
-        ngn_out_update_windows(m, ngn);
-        h2_ngn_shed_done_task(m->ngn_shed, ngn, task);
-        
-        if (status != APR_SUCCESS && stream 
-            && h2_task_can_redo(task) 
-            && !h2_ihash_get(m->sredo, stream->id)) {
-            h2_ihash_add(m->sredo, stream);
-        }
-
-        if (task->engine) { 
-            /* cannot report that as done until engine returns */
-        }
-        else {
-            task_done(m, task, ngn);
-        }
-
-        H2_MPLX_LEAVE(m);
-    }
-}
-
-/*******************************************************************************
  * mplx master events dispatching
  ******************************************************************************/
 
Index: httpd-2.4.23/modules/http2/h2_mplx.h
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_mplx.h	2019-04-02 13:39:34.072792571 +0200
+++ httpd-2.4.23/modules/http2/h2_mplx.h	2019-04-02 13:42:32.649683136 +0200
@@ -46,8 +46,6 @@ struct h2_request;
 struct apr_thread_cond_t;
 struct h2_workers;
 struct h2_iqueue;
-struct h2_ngn_shed;
-struct h2_req_engine;
 
 #include <apr_queue.h>
 
@@ -85,7 +83,6 @@ struct h2_mplx {
 
     apr_thread_mutex_t *lock;
     struct apr_thread_cond_t *added_output;
-    struct apr_thread_cond_t *task_thawed;
     struct apr_thread_cond_t *join_wait;
     
     apr_size_t stream_max_mem;
@@ -94,8 +91,6 @@ struct h2_mplx {
     apr_array_header_t *spare_slaves; /* spare slave connections */
     
     struct h2_workers *workers;
-    
-    struct h2_ngn_shed *ngn_shed;
 };
 
 
@@ -110,8 +105,7 @@ apr_status_t h2_mplx_child_init(apr_pool
  * Create the multiplexer for the given HTTP2 session. 
  * Implicitly has reference count 1.
  */
-h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *master, 
-                        const struct h2_config *conf, 
+h2_mplx *h2_mplx_create(conn_rec *c, server_rec *s, apr_pool_t *master,
                         struct h2_workers *workers);
 
 /**
@@ -302,28 +296,4 @@ APR_RING_INSERT_TAIL((b), ap__b, h2_mplx
  */
 apr_status_t h2_mplx_idle(h2_mplx *m);
 
-/*******************************************************************************
- * h2_req_engine handling
- ******************************************************************************/
-
-typedef void h2_output_consumed(void *ctx, conn_rec *c, apr_off_t consumed);
-typedef apr_status_t h2_mplx_req_engine_init(struct h2_req_engine *engine, 
-                                             const char *id, 
-                                             const char *type,
-                                             apr_pool_t *pool, 
-                                             apr_size_t req_buffer_size,
-                                             request_rec *r,
-                                             h2_output_consumed **pconsumed,
-                                             void **pbaton);
-
-apr_status_t h2_mplx_req_engine_push(const char *ngn_type, 
-                                     request_rec *r, 
-                                     h2_mplx_req_engine_init *einit);
-apr_status_t h2_mplx_req_engine_pull(struct h2_req_engine *ngn, 
-                                     apr_read_type_e block, 
-                                     int capacity, 
-                                     request_rec **pr);
-void h2_mplx_req_engine_done(struct h2_req_engine *ngn, conn_rec *r_conn,
-                             apr_status_t status);
-
 #endif /* defined(__mod_h2__h2_mplx__) */
Index: httpd-2.4.23/modules/http2/h2_proxy_session.c
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_proxy_session.c	2019-04-02 13:39:34.224793330 +0200
+++ httpd-2.4.23/modules/http2/h2_proxy_session.c	2019-04-02 13:39:34.260793510 +0200
@@ -428,12 +428,6 @@ static int stream_response_data(nghttp2_
                                   stream_id, NGHTTP2_STREAM_CLOSED);
         return NGHTTP2_ERR_STREAM_CLOSING;
     }
-    if (stream->standalone) {
-        nghttp2_session_consume(ngh2, stream_id, len);
-        ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, stream->r,
-                      "h2_proxy_session(%s): stream %d, win_update %d bytes",
-                      session->id, stream_id, (int)len);
-    }
     return 0;
 }
 
@@ -640,7 +634,7 @@ h2_proxy_session *h2_proxy_session_setup
         
         nghttp2_option_new(&option);
         nghttp2_option_set_peer_max_concurrent_streams(option, 100);
-        nghttp2_option_set_no_auto_window_update(option, 1);
+        nghttp2_option_set_no_auto_window_update(option, 0);
         
         nghttp2_session_client_new2(&session->ngh2, cbs, session, option);
         
@@ -652,10 +646,12 @@ h2_proxy_session *h2_proxy_session_setup
     }
     else {
         h2_proxy_session *session = p_conn->data;
-        apr_interval_time_t age = apr_time_now() - session->last_frame_received;
-        if (age > apr_time_from_sec(1)) {
-            session->check_ping = 1;
-            nghttp2_submit_ping(session->ngh2, 0, (const uint8_t *)"nevergonnagiveyouup");
+        if (!session->check_ping) {
+            apr_interval_time_t age = apr_time_now() - session->last_frame_received;
+            if (age > apr_time_from_sec(1)) {
+                session->check_ping = 1;
+                nghttp2_submit_ping(session->ngh2, 0, (const uint8_t *)"nevergonnagiveyouup");
+            }
         }
     }
     return p_conn->data;
@@ -1542,42 +1538,3 @@ typedef struct {
     int updated;
 } win_update_ctx;
 
-static int win_update_iter(void *udata, void *val)
-{
-    win_update_ctx *ctx = udata;
-    h2_proxy_stream *stream = val;
-    
-    if (stream->r && stream->r->connection == ctx->c) {
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, ctx->session->c, 
-                      "h2_proxy_session(%s-%d): win_update %ld bytes",
-                      ctx->session->id, (int)stream->id, (long)ctx->bytes);
-        nghttp2_session_consume(ctx->session->ngh2, stream->id, ctx->bytes);
-        ctx->updated = 1;
-        return 0;
-    }
-    return 1;
-}
-
-
-void h2_proxy_session_update_window(h2_proxy_session *session, 
-                                    conn_rec *c, apr_off_t bytes)
-{
-    if (!h2_proxy_ihash_empty(session->streams)) {
-        win_update_ctx ctx;
-        ctx.session = session;
-        ctx.c = c;
-        ctx.bytes = bytes;
-        ctx.updated = 0;
-        h2_proxy_ihash_iter(session->streams, win_update_iter, &ctx);
-        
-        if (!ctx.updated) {
-            /* could not find the stream any more, possibly closed, update
-             * the connection window at least */
-            ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c, 
-                          "h2_proxy_session(%s): win_update conn %ld bytes",
-                          session->id, (long)bytes);
-            nghttp2_session_consume_connection(session->ngh2, (size_t)bytes);
-        }
-    }
-}
-
Index: httpd-2.4.23/modules/http2/h2_proxy_session.h
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_proxy_session.h	2019-04-02 13:39:34.072792571 +0200
+++ httpd-2.4.23/modules/http2/h2_proxy_session.h	2019-04-02 13:39:34.260793510 +0200
@@ -119,9 +119,6 @@ void h2_proxy_session_cancel_all(h2_prox
 
 void h2_proxy_session_cleanup(h2_proxy_session *s, h2_proxy_request_done *done);
 
-void h2_proxy_session_update_window(h2_proxy_session *s, 
-                                    conn_rec *c, apr_off_t bytes);
-
 #define H2_PROXY_REQ_URL_NOTE   "h2-proxy-req-url"
 
 #endif /* h2_proxy_session_h */
Index: httpd-2.4.23/modules/http2/h2_request.c
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_request.c	2019-04-02 13:39:34.196793190 +0200
+++ httpd-2.4.23/modules/http2/h2_request.c	2019-04-02 13:42:32.649683136 +0200
@@ -16,6 +16,7 @@
 #include <assert.h>
 
 #include <apr_strings.h>
+#include <ap_mmn.h>
 
 #include <httpd.h>
 #include <http_core.h>
@@ -83,8 +84,7 @@ apr_status_t h2_request_rcreate(h2_reque
     req->path      = path;
     req->headers   = apr_table_make(pool, 10);
     if (r->server) {
-        req->serialize = h2_config_geti(h2_config_sget(r->server), 
-                                        H2_CONF_SER_HEADERS);
+        req->serialize = h2_config_rgeti(r, H2_CONF_SER_HEADERS);
     }
 
     x.pool = pool;
@@ -205,13 +205,11 @@ h2_request *h2_request_clone(apr_pool_t
     return dst;
 }
 
-request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c)
+#if !AP_MODULE_MAGIC_AT_LEAST(20150222, 13)
+static request_rec *my_ap_create_request(conn_rec *c)
 {
-    int access_status = HTTP_OK;    
-    const char *rpath;
     apr_pool_t *p;
     request_rec *r;
-    const char *s;
 
     apr_pool_create(&p, c->pool);
     apr_pool_tag(p, "request");
@@ -225,8 +223,8 @@ request_rec *h2_request_create_rec(const
     r->ap_auth_type    = NULL;
     
     r->allowed_methods = ap_make_method_list(p, 2);
-    
-    r->headers_in      = apr_table_clone(r->pool, req->headers);
+
+    r->headers_in      = apr_table_make(r->pool, 5);
     r->trailers_in     = apr_table_make(r->pool, 5);
     r->subprocess_env  = apr_table_make(r->pool, 25);
     r->headers_out     = apr_table_make(r->pool, 12);
@@ -261,11 +259,29 @@ request_rec *h2_request_create_rec(const
     r->useragent_addr = c->client_addr;
     r->useragent_ip = c->client_ip;
     
+    return r;
+}
+#endif
+
+request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c)
+{
+    int access_status = HTTP_OK;
+    const char *rpath;
+    const char *s;
+
+#if AP_MODULE_MAGIC_AT_LEAST(20150222, 13)
+    request_rec *r = ap_create_request(c);
+#else
+    request_rec *r = my_ap_create_request(c);
+#endif
+
+    r->headers_in = apr_table_clone(r->pool, req->headers);
+
     ap_run_pre_read_request(r, c);
     
     /* Time to populate r with the data we have. */
     r->request_time = req->request_time;
-    r->method = req->method;
+    r->method = apr_pstrdup(r->pool, req->method);
     /* Provide quick information about the request method as soon as known */
     r->method_number = ap_method_number_of(r->method);
     if (r->method_number == M_GET && r->method[0] == 'H') {
@@ -336,3 +352,4 @@ traceout:
 }
 
 
+
Index: httpd-2.4.23/modules/http2/h2_session.c
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_session.c	2019-04-02 13:39:34.224793330 +0200
+++ httpd-2.4.23/modules/http2/h2_session.c	2019-04-02 13:42:32.653683156 +0200
@@ -494,9 +494,7 @@ static int on_send_data_cb(nghttp2_sessi
         return NGHTTP2_ERR_WOULDBLOCK;
     }
 
-    if (frame->data.padlen > H2_MAX_PADLEN) {
-        return NGHTTP2_ERR_PROTO;
-    }
+    ap_assert(frame->data.padlen <= (H2_MAX_PADLEN+1));
     padlen = (unsigned char)frame->data.padlen;
     
     stream = h2_session_stream_get(session, stream_id);
@@ -512,8 +510,9 @@ static int on_send_data_cb(nghttp2_sessi
                   H2_STRM_MSG(stream, "send_data_cb for %ld bytes"),
                   (long)length);
                   
-    status = h2_conn_io_write(&session->io, (const char *)framehd, 9);
+    status = h2_conn_io_write(&session->io, (const char *)framehd, H2_FRAME_HDR_LEN);
     if (padlen && status == APR_SUCCESS) {
+        --padlen;
         status = h2_conn_io_write(&session->io, (const char *)&padlen, 1);
     }
     
@@ -621,6 +620,39 @@ static int on_invalid_header_cb(nghttp2_
 }
 #endif
 
+static ssize_t select_padding_cb(nghttp2_session *ngh2,
+                                 const nghttp2_frame *frame,
+                                 size_t max_payloadlen, void *user_data)
+{
+    h2_session *session = user_data;
+    ssize_t frame_len = frame->hd.length + H2_FRAME_HDR_LEN; /* the total length without padding */
+    ssize_t padded_len = frame_len;
+
+    /* Determine # of padding bytes to append to frame. Unless session->padding_always
+     * the number my be capped by the ui.write_size that currently applies.
+     */
+    if (session->padding_max) {
+        int n = ap_random_pick(0, session->padding_max);
+        padded_len = H2MIN(max_payloadlen + H2_FRAME_HDR_LEN, frame_len + n);
+    }
+
+    if (padded_len != frame_len) {
+        if (!session->padding_always && session->io.write_size
+            && (padded_len > session->io.write_size)
+            && (frame_len <= session->io.write_size)) {
+            padded_len = session->io.write_size;
+        }
+        if (APLOGctrace2(session->c)) {
+            ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c,
+                          "select padding from [%d, %d]: %d (frame length: 0x%04x, write size: %d)",
+                          (int)frame_len, (int)max_payloadlen+H2_FRAME_HDR_LEN,
+                          (int)(padded_len - frame_len), (int)padded_len, (int)session->io.write_size);
+        }
+        return padded_len - H2_FRAME_HDR_LEN;
+    }
+    return frame->hd.length;
+}
+
 #define NGH2_SET_CALLBACK(callbacks, name, fn)\
 nghttp2_session_callbacks_set_##name##_callback(callbacks, fn)
 
@@ -646,6 +678,7 @@ static apr_status_t init_callbacks(conn_
 #ifdef H2_NG2_INVALID_HEADER_CB
     NGH2_SET_CALLBACK(*pcb, on_invalid_header, on_invalid_header_cb);
 #endif
+    NGH2_SET_CALLBACK(*pcb, select_padding, select_padding_cb);
     return APR_SUCCESS;
 }
 
@@ -756,9 +789,8 @@ static apr_status_t session_pool_cleanup
 {
     conn_rec *c = data;
     h2_session *session;
-    h2_ctx *ctx = h2_ctx_get(c, 0);
     
-    if (ctx && (session = h2_ctx_session_get(ctx))) {
+    if ((session = h2_ctx_get_session(c))) {
         /* if the session is still there, now is the last chance
          * to perform cleanup. Normally, cleanup should have happened
          * earlier in the connection pre_close. Main reason is that
@@ -774,11 +806,8 @@ static apr_status_t session_pool_cleanup
     return APR_SUCCESS;
 }
 
-static apr_status_t h2_session_create_int(h2_session **psession,
-                                          conn_rec *c,
-                                          request_rec *r,
-                                          h2_ctx *ctx, 
-                                          h2_workers *workers)
+apr_status_t h2_session_create(h2_session **psession, conn_rec *c, request_rec *r,
+                               server_rec *s, h2_workers *workers)
 {
     nghttp2_session_callbacks *callbacks = NULL;
     nghttp2_option *options = NULL;
@@ -819,19 +848,16 @@ static apr_status_t h2_session_create_in
     session->id = c->id;
     session->c = c;
     session->r = r;
-    session->s = h2_ctx_server_get(ctx);
+    session->s = s;
     session->pool = pool;
-    session->config = h2_config_sget(session->s);
     session->workers = workers;
     
     session->state = H2_SESSION_ST_INIT;
     session->local.accepting = 1;
     session->remote.accepting = 1;
     
-    session->max_stream_count = h2_config_geti(session->config, 
-                                               H2_CONF_MAX_STREAMS);
-    session->max_stream_mem = h2_config_geti(session->config, 
-                                             H2_CONF_STREAM_MAX_MEM);
+    session->max_stream_count = h2_config_sgeti(s, H2_CONF_MAX_STREAMS);
+    session->max_stream_mem = h2_config_sgeti(s, H2_CONF_STREAM_MAX_MEM);
     
     status = apr_thread_cond_create(&session->iowait, session->pool);
     if (status != APR_SUCCESS) {
@@ -861,14 +887,18 @@ static apr_status_t h2_session_create_in
     session->monitor->on_state_event = on_stream_state_event;
     session->monitor->on_event = on_stream_event;
     
-    session->mplx = h2_mplx_create(c, session->pool, session->config, 
-                                   workers);
+    session->mplx = h2_mplx_create(c, s, session->pool, workers);
     
     /* connection input filter that feeds the session */
     session->cin = h2_filter_cin_create(session);
     ap_add_input_filter("H2_IN", session->cin, r, c);
     
-    h2_conn_io_init(&session->io, c, session->config);
+    h2_conn_io_init(&session->io, c, s);
+    session->padding_max = h2_config_sgeti(s, H2_CONF_PADDING_BITS);
+    if (session->padding_max) {
+        session->padding_max = (0x01 << session->padding_max) - 1;
+    }
+    session->padding_always = h2_config_sgeti(s, H2_CONF_PADDING_ALWAYS);
     session->bbtmp = apr_brigade_create(session->pool, c->bucket_alloc);
     
     status = init_callbacks(c, &callbacks);
@@ -887,8 +917,7 @@ static apr_status_t h2_session_create_in
         apr_pool_destroy(pool);
         return status;
     }
-    nghttp2_option_set_peer_max_concurrent_streams(
-                                                   options, (uint32_t)session->max_stream_count);
+    nghttp2_option_set_peer_max_concurrent_streams(options, (uint32_t)session->max_stream_count);
     /* We need to handle window updates ourself, otherwise we
      * get flooded by nghttp2. */
     nghttp2_option_set_no_auto_window_update(options, 1);
@@ -906,7 +935,7 @@ static apr_status_t h2_session_create_in
         return APR_ENOMEM;
     }
     
-    n = h2_config_geti(session->config, H2_CONF_PUSH_DIARY_SIZE);
+    n = h2_config_sgeti(s, H2_CONF_PUSH_DIARY_SIZE);
     session->push_diary = h2_push_diary_create(session->pool, n);
     
     if (APLOGcdebug(c)) {
@@ -923,20 +952,9 @@ static apr_status_t h2_session_create_in
                       (int)session->push_diary->N);
     }
     
-    apr_pool_pre_cleanup_register(pool, c, session_pool_cleanup);    
-    return APR_SUCCESS;
-}
-
-apr_status_t h2_session_create(h2_session **psession, 
-                               conn_rec *c, h2_ctx *ctx, h2_workers *workers)
-{
-    return h2_session_create_int(psession, c, NULL, ctx, workers);
-}
+    apr_pool_pre_cleanup_register(pool, c, session_pool_cleanup);
 
-apr_status_t h2_session_rcreate(h2_session **psession, 
-                                request_rec *r, h2_ctx *ctx, h2_workers *workers)
-{
-    return h2_session_create_int(psession, r->connection, r, ctx, workers);
+    return APR_SUCCESS;
 }
 
 static apr_status_t h2_session_start(h2_session *session, int *rv)
@@ -1003,7 +1021,7 @@ static apr_status_t h2_session_start(h2_
     settings[slen].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
     settings[slen].value = (uint32_t)session->max_stream_count;
     ++slen;
-    win_size = h2_config_geti(session->config, H2_CONF_WIN_SIZE);
+    win_size = h2_config_sgeti(session->s, H2_CONF_WIN_SIZE);
     if (win_size != H2_INITIAL_WINDOW_SIZE) {
         settings[slen].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
         settings[slen].value = win_size;
@@ -1279,7 +1297,7 @@ int h2_session_push_enabled(h2_session *
 {
     /* iff we can and they can and want */
     return (session->remote.accepting /* remote GOAWAY received */
-            && h2_config_geti(session->config, H2_CONF_PUSH)
+            && h2_config_sgeti(session->s, H2_CONF_PUSH)
             && nghttp2_session_get_remote_settings(session->ngh2, 
                    NGHTTP2_SETTINGS_ENABLE_PUSH));
 }
@@ -1323,6 +1341,7 @@ static apr_status_t on_stream_headers(h2
                                       int eos)
 {
     apr_status_t status = APR_SUCCESS;
+    const char *s;
     int rv = 0;
 
     ap_assert(session);
@@ -1390,8 +1409,12 @@ static apr_status_t on_stream_headers(h2
             && (headers->status < 400)
             && (headers->status != 304)
             && h2_session_push_enabled(session)) {
-            
-            h2_stream_submit_pushes(stream, headers);
+            /* PUSH is possibe and enabled on server, unless the request
+             * denies it, submit resources to push */
+            s = apr_table_get(headers->notes, H2_PUSH_MODE_NOTE);
+            if (!s || strcmp(s, "0")) {
+                h2_stream_submit_pushes(stream, headers);
+            }
         }
         
         if (!stream->pref_priority) {
@@ -1413,7 +1436,7 @@ static apr_status_t on_stream_headers(h2
         }
         
         if (headers->status == 103 
-            && !h2_config_geti(session->config, H2_CONF_EARLY_HINTS)) {
+            && !h2_config_sgeti(session->s, H2_CONF_EARLY_HINTS)) {
             /* suppress sending this to the client, it might have triggered 
              * pushes and served its purpose nevertheless */
             rv = 0;
@@ -2088,7 +2111,7 @@ apr_status_t h2_session_process(h2_sessi
         switch (session->state) {
             case H2_SESSION_ST_INIT:
                 ap_update_child_status_from_conn(c->sbh, SERVER_BUSY_READ, c);
-                if (!h2_is_acceptable_connection(c, 1)) {
+                if (!h2_is_acceptable_connection(c, session->r, 1)) {
                     update_child_status(session, SERVER_BUSY_READ, 
                                         "inadequate security");
                     h2_session_shutdown(session, 
Index: httpd-2.4.23/modules/http2/h2_session.h
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_session.h	2019-04-02 13:39:34.196793190 +0200
+++ httpd-2.4.23/modules/http2/h2_session.h	2019-04-02 13:42:32.653683156 +0200
@@ -79,12 +79,13 @@ typedef struct h2_session {
     request_rec *r;                 /* the request that started this in case
                                      * of 'h2c', NULL otherwise */
     server_rec *s;                  /* server/vhost we're starting on */
-    const struct h2_config *config; /* Relevant config for this session */
     apr_pool_t *pool;               /* pool to use in session */
     struct h2_mplx *mplx;           /* multiplexer for stream data */
     struct h2_workers *workers;     /* for executing stream tasks */
     struct h2_filter_cin *cin;      /* connection input filter context */
     h2_conn_io io;                  /* io on httpd conn filters */
+    int padding_max;                /* max number of padding bytes */
+    int padding_always;             /* padding has precedence over I/O optimizations */
     struct nghttp2_session *ngh2;   /* the nghttp2 session (internal use) */
 
     h2_session_state state;         /* state session is in */
@@ -141,27 +142,15 @@ const char *h2_session_state_str(h2_sess
  * The session will apply the configured parameter.
  * @param psession pointer receiving the created session on success or NULL
  * @param c       the connection to work on
+ * @param r       optional request when protocol was upgraded
  * @param cfg     the module config to apply
  * @param workers the worker pool to use
  * @return the created session
  */
 apr_status_t h2_session_create(h2_session **psession,
-                               conn_rec *c, struct h2_ctx *ctx, 
+                               conn_rec *c, request_rec *r, server_rec *,
                                struct h2_workers *workers);
 
-/**
- * Create a new h2_session for the given request.
- * The session will apply the configured parameter.
- * @param psession pointer receiving the created session on success or NULL
- * @param r       the request that was upgraded
- * @param cfg     the module config to apply
- * @param workers the worker pool to use
- * @return the created session
- */
-apr_status_t h2_session_rcreate(h2_session **psession,
-                                request_rec *r, struct h2_ctx *ctx,
-                                struct h2_workers *workers);
-
 void h2_session_event(h2_session *session, h2_session_event_t ev, 
                              int err, const char *msg);
 
Index: httpd-2.4.23/modules/http2/h2_stream.c
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_stream.c	2019-04-02 13:39:34.224793330 +0200
+++ httpd-2.4.23/modules/http2/h2_stream.c	2019-04-02 13:42:32.653683156 +0200
@@ -364,9 +364,8 @@ void h2_stream_dispatch(h2_stream *strea
 static void set_policy_for(h2_stream *stream, h2_request *r) 
 {
     int enabled = h2_session_push_enabled(stream->session);
-    stream->push_policy = h2_push_policy_determine(r->headers, stream->pool, 
-                                                   enabled);
-    r->serialize = h2_config_geti(stream->session->config, H2_CONF_SER_HEADERS);
+    stream->push_policy = h2_push_policy_determine(r->headers, stream->pool, enabled);
+    r->serialize = h2_config_sgeti(stream->session->s, H2_CONF_SER_HEADERS);
 }
 
 apr_status_t h2_stream_send_frame(h2_stream *stream, int ftype, int flags, size_t frame_len)
@@ -854,7 +853,7 @@ apr_status_t h2_stream_out_prepare(h2_st
      * is requested. But we can reduce the size in case the master
      * connection operates in smaller chunks. (TSL warmup) */
     if (stream->session->io.write_size > 0) {
-        max_chunk = stream->session->io.write_size - 9; /* header bits */ 
+        max_chunk = stream->session->io.write_size - H2_FRAME_HDR_LEN;
     }
     requested = (*plen > 0)? H2MIN(*plen, max_chunk) : max_chunk;
     
@@ -986,7 +985,7 @@ const h2_priority *h2_stream_get_priorit
         const char *ctype = apr_table_get(response->headers, "content-type");
         if (ctype) {
             /* FIXME: Not good enough, config needs to come from request->server */
-            return h2_config_get_priority(stream->session->config, ctype);
+            return h2_cconfig_get_priority(stream->session->c, ctype);
         }
     }
     return NULL;
Index: httpd-2.4.23/modules/http2/h2_switch.c
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_switch.c	2019-04-02 13:39:34.196793190 +0200
+++ httpd-2.4.23/modules/http2/h2_switch.c	2019-04-02 13:42:32.653683156 +0200
@@ -54,7 +54,6 @@ static int h2_protocol_propose(conn_rec
     int is_tls = h2_h2_is_tls(c);
     const char **protos = is_tls? h2_tls_protos : h2_clear_protos;
     
-    (void)s;
     if (!h2_mpm_supported()) {
         return DECLINED;
     }
@@ -67,7 +66,7 @@ static int h2_protocol_propose(conn_rec
         return DECLINED;
     }
     
-    if (!h2_is_acceptable_connection(c, 0)) {
+    if (!h2_is_acceptable_connection(c, r, 0)) {
         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(03084)
                       "protocol propose: connection requirements not met");
         return DECLINED;
@@ -80,7 +79,7 @@ static int h2_protocol_propose(conn_rec
          */
         const char *p;
         
-        if (!h2_allows_h2_upgrade(c)) {
+        if (!h2_allows_h2_upgrade(r)) {
             return DECLINED;
         }
          
@@ -149,7 +148,7 @@ static int h2_protocol_switch(conn_rec *
         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
                       "switching protocol to '%s'", protocol);
         h2_ctx_protocol_set(ctx, protocol);
-        h2_ctx_server_set(ctx, s);
+        h2_ctx_server_update(ctx, s);
         
         if (r != NULL) {
             apr_status_t status;
@@ -163,8 +162,8 @@ static int h2_protocol_switch(conn_rec *
             ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER");
             
             /* Ok, start an h2_conn on this one. */
-            h2_ctx_server_set(ctx, r->server);
-            status = h2_conn_setup(ctx, r->connection, r);
+            status = h2_conn_setup(c, r, s);
+
             if (status != APR_SUCCESS) {
                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(03088)
                               "session setup");
@@ -172,7 +171,7 @@ static int h2_protocol_switch(conn_rec *
                 return !OK;
             }
             
-            h2_conn_run(ctx, c);
+            h2_conn_run(c);
         }
         return OK;
     }
Index: httpd-2.4.23/modules/http2/h2_task.c
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_task.c	2019-04-02 13:39:34.196793190 +0200
+++ httpd-2.4.23/modules/http2/h2_task.c	2019-04-02 13:39:34.264793530 +0200
@@ -96,7 +96,7 @@ static apr_status_t send_out(h2_task *ta
     apr_brigade_length(bb, 0, &written);
     H2_TASK_OUT_LOG(APLOG_TRACE2, task, bb, "h2_task send_out");
     h2_beam_log(task->output.beam, task->c, APLOG_TRACE2, "send_out(before)");
-    /* engines send unblocking */
+
     status = h2_beam_send(task->output.beam, bb, 
                           block? APR_BLOCK_READ : APR_NONBLOCK_READ);
     h2_beam_log(task->output.beam, task->c, APLOG_TRACE2, "send_out(after)");
@@ -132,26 +132,9 @@ static apr_status_t slave_out(h2_task *t
     apr_status_t rv = APR_SUCCESS;
     int flush = 0, blocking;
     
-    if (task->frozen) {
-        h2_util_bb_log(task->c, task->stream_id, APLOG_TRACE2,
-                       "frozen task output write, ignored", bb);
-        while (!APR_BRIGADE_EMPTY(bb)) {
-            b = APR_BRIGADE_FIRST(bb);
-            if (AP_BUCKET_IS_EOR(b)) {
-                APR_BUCKET_REMOVE(b);
-                task->eor = b;
-            }
-            else {
-                apr_bucket_delete(b);
-            }
-        }
-        return APR_SUCCESS;
-    }
-
 send:
-    /* we send block once we opened the output, so someone is there
-     * reading it *and* the task is not assigned to a h2_req_engine */
-    blocking = (!task->assigned && task->output.opened);
+    /* we send block once we opened the output, so someone is there reading it */
+    blocking = task->output.opened;
     for (b = APR_BRIGADE_FIRST(bb);
          b != APR_BRIGADE_SENTINEL(bb);
          b = APR_BUCKET_NEXT(b)) {
@@ -235,7 +218,7 @@ static apr_status_t h2_filter_slave_in(a
     apr_size_t rmax = ((readbytes <= APR_SIZE_MAX)? 
                        (apr_size_t)readbytes : APR_SIZE_MAX);
     
-    task = h2_ctx_cget_task(f->c);
+    task = h2_ctx_get_task(f->c);
     ap_assert(task);
 
     if (trace1) {
@@ -309,11 +292,9 @@ static apr_status_t h2_filter_slave_in(a
         }
     }
     
-    /* Nothing there, no more data to get. Return APR_EAGAIN on
-     * speculative reads, this is ap_check_pipeline()'s trick to
-     * see if the connection needs closing. */
+    /* Nothing there, no more data to get. Return. */
     if (status == APR_EOF && APR_BRIGADE_EMPTY(task->input.bb)) {
-        return (mode == AP_MODE_SPECULATIVE)? APR_EAGAIN : APR_EOF;
+        return status;
     }
 
     if (trace1) {
@@ -378,7 +359,7 @@ static apr_status_t h2_filter_slave_in(a
 static apr_status_t h2_filter_slave_output(ap_filter_t* filter,
                                            apr_bucket_brigade* brigade)
 {
-    h2_task *task = h2_ctx_cget_task(filter->c);
+    h2_task *task = h2_ctx_get_task(filter->c);
     apr_status_t status;
     
     ap_assert(task);
@@ -391,7 +372,7 @@ static apr_status_t h2_filter_slave_outp
 
 static apr_status_t h2_filter_parse_h1(ap_filter_t* f, apr_bucket_brigade* bb)
 {
-    h2_task *task = h2_ctx_cget_task(f->c);
+    h2_task *task = h2_ctx_get_task(f->c);
     apr_status_t status;
     
     ap_assert(task);
@@ -501,9 +482,9 @@ static int h2_task_pre_conn(conn_rec* c,
     
     ctx = h2_ctx_get(c, 0);
     (void)arg;
-    if (h2_ctx_is_task(ctx)) {
+    if (ctx->task) {
         ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
-                      "h2_h2, pre_connection, found stream task");
+                      "h2_slave(%s), pre_connection, adding filters", c->log_id);
         ap_add_input_filter("H2_SLAVE_IN", NULL, NULL, c);
         ap_add_output_filter("H2_PARSE_H1", NULL, NULL, c);
         ap_add_output_filter("H2_SLAVE_OUT", NULL, NULL, c);
@@ -524,6 +505,7 @@ h2_task *h2_task_create(conn_rec *slave,
     ap_assert(req);
 
     apr_pool_create(&pool, slave->pool);
+    apr_pool_tag(pool, "h2_task");
     task = apr_pcalloc(pool, sizeof(h2_task));
     if (task == NULL) {
         return NULL;
@@ -544,7 +526,6 @@ h2_task *h2_task_create(conn_rec *slave,
 void h2_task_destroy(h2_task *task)
 {
     if (task->output.beam) {
-        h2_beam_log(task->output.beam, task->c, APLOG_TRACE2, "task_destroy");
         h2_beam_destroy(task->output.beam);
         task->output.beam = NULL;
     }
@@ -598,7 +579,6 @@ apr_status_t h2_task_do(h2_task *task, a
             slave_id = worker_id; 
         }
         task->c->id = (c->master->id << free_bits)^slave_id;
-        c->keepalive = AP_CONN_KEEPALIVE;
     }
         
     h2_beam_create(&task->output.beam, c->pool, task->stream_id, "output", 
@@ -633,18 +613,9 @@ apr_status_t h2_task_do(h2_task *task, a
     task->c->current_thread = thread; 
     ap_run_process_connection(c);
     
-    if (task->frozen) {
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
-                      "h2_task(%s): process_conn returned frozen task", 
-                      task->id);
-        /* cleanup delayed */
-        return APR_EAGAIN;
-    }
-    else {
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
-                      "h2_task(%s): processing done", task->id);
-        return output_finish(task);
-    }
+    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
+                  "h2_task(%s): processing done", task->id);
+    return output_finish(task);
 }
 
 static apr_status_t h2_task_process_request(h2_task *task, conn_rec *c)
@@ -682,14 +653,8 @@ static apr_status_t h2_task_process_requ
         
         ap_process_request(r);
         
-        if (task->frozen) {
-            ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
-                          "h2_task(%s): process_request frozen", task->id);
-        }
-        else {
-            ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
-                          "h2_task(%s): process_request done", task->id);
-        }
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
+                      "h2_task(%s): process_request done", task->id);
         
         /* After the call to ap_process_request, the
          * request pool may have been deleted.  We set
@@ -724,7 +689,7 @@ static int h2_task_process_conn(conn_rec
     }
     
     ctx = h2_ctx_get(c, 0);
-    if (h2_ctx_is_task(ctx)) {
+    if (ctx->task) {
         if (!ctx->task->request->serialize) {
             ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, 
                           "h2_h2, processing request directly");
@@ -741,28 +706,3 @@ static int h2_task_process_conn(conn_rec
     return DECLINED;
 }
 
-apr_status_t h2_task_freeze(h2_task *task)
-{   
-    if (!task->frozen) {
-        task->frozen = 1;
-        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, task->c, APLOGNO(03406) 
-                      "h2_task(%s), frozen", task->id);
-    }
-    return APR_SUCCESS;
-}
-
-apr_status_t h2_task_thaw(h2_task *task)
-{
-    if (task->frozen) {
-        task->frozen = 0;
-        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, task->c, APLOGNO(03407) 
-                      "h2_task(%s), thawed", task->id);
-    }
-    task->thawed = 1;
-    return APR_SUCCESS;
-}
-
-int h2_task_has_thawed(h2_task *task)
-{
-    return task->thawed;
-}
Index: httpd-2.4.23/modules/http2/h2_task.h
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_task.h	2019-04-02 13:39:34.076792591 +0200
+++ httpd-2.4.23/modules/http2/h2_task.h	2019-04-02 13:42:32.653683156 +0200
@@ -41,7 +41,6 @@ struct h2_bucket_beam;
 struct h2_conn;
 struct h2_mplx;
 struct h2_task;
-struct h2_req_engine;
 struct h2_request;
 struct h2_response_parser;
 struct h2_stream;
@@ -79,17 +78,14 @@ struct h2_task {
     struct h2_mplx *mplx;
     
     unsigned int filters_set    : 1;
-    unsigned int frozen         : 1;
-    unsigned int thawed         : 1;
     unsigned int worker_started : 1; /* h2_worker started processing */
-    unsigned int worker_done    : 1; /* h2_worker finished */
+
+    int worker_done;                 /* h2_worker finished */
+    int done_done;                   /* task_done has been handled */
     
     apr_time_t started_at;           /* when processing started */
     apr_time_t done_at;              /* when processing was done */
     apr_bucket *eor;
-    
-    struct h2_req_engine *engine;   /* engine hosted by this task */
-    struct h2_req_engine *assigned; /* engine that task has been assigned to */
 };
 
 h2_task *h2_task_create(conn_rec *slave, int stream_id,
@@ -119,8 +115,4 @@ apr_status_t h2_task_init(apr_pool_t *po
 extern APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_in) *h2_task_logio_add_bytes_in;
 extern APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_out) *h2_task_logio_add_bytes_out;
 
-apr_status_t h2_task_freeze(h2_task *task);
-apr_status_t h2_task_thaw(h2_task *task);
-int h2_task_has_thawed(h2_task *task);
-
 #endif /* defined(__mod_h2__h2_task__) */
Index: httpd-2.4.23/modules/http2/h2_version.h
===================================================================
--- httpd-2.4.23.orig/modules/http2/h2_version.h	2019-04-02 13:39:34.224793330 +0200
+++ httpd-2.4.23/modules/http2/h2_version.h	2019-04-02 13:39:34.264793530 +0200
@@ -26,7 +26,7 @@
  * @macro
  * Version number of the http2 module as c string
  */
-#define MOD_HTTP2_VERSION "1.11.4"
+#define MOD_HTTP2_VERSION "1.14.1"
 
 /**
  * @macro
@@ -34,7 +34,6 @@
  * 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 0x010b04
-
+#define MOD_HTTP2_VERSION_NUM 0x010e01
 
 #endif /* mod_h2_h2_version_h */
Index: httpd-2.4.23/modules/http2/mod_http2.c
===================================================================
--- httpd-2.4.23.orig/modules/http2/mod_http2.c	2019-04-02 13:39:34.196793190 +0200
+++ httpd-2.4.23/modules/http2/mod_http2.c	2019-04-02 13:42:32.653683156 +0200
@@ -171,27 +171,6 @@ static char *http2_var_lookup(apr_pool_t
                          conn_rec *, request_rec *, char *name);
 static int http2_is_h2(conn_rec *);
 
-static apr_status_t http2_req_engine_push(const char *ngn_type, 
-                                          request_rec *r, 
-                                          http2_req_engine_init *einit)
-{
-    return h2_mplx_req_engine_push(ngn_type, r, einit);
-}
-
-static apr_status_t http2_req_engine_pull(h2_req_engine *ngn, 
-                                          apr_read_type_e block, 
-                                          int capacity, 
-                                          request_rec **pr)
-{
-    return h2_mplx_req_engine_pull(ngn, block, capacity, pr);
-}
-
-static void http2_req_engine_done(h2_req_engine *ngn, conn_rec *r_conn,
-                                  apr_status_t status)
-{
-    h2_mplx_req_engine_done(ngn, r_conn, status);
-}
-
 static void http2_get_num_workers(server_rec *s, int *minw, int *maxw)
 {
     h2_get_num_workers(s, minw, maxw);
@@ -219,9 +198,6 @@ static void h2_hooks(apr_pool_t *pool)
     
     APR_REGISTER_OPTIONAL_FN(http2_is_h2);
     APR_REGISTER_OPTIONAL_FN(http2_var_lookup);
-    APR_REGISTER_OPTIONAL_FN(http2_req_engine_push);
-    APR_REGISTER_OPTIONAL_FN(http2_req_engine_pull);
-    APR_REGISTER_OPTIONAL_FN(http2_req_engine_done);
     APR_REGISTER_OPTIONAL_FN(http2_get_num_workers);
 
     ap_log_perror(APLOG_MARK, APLOG_TRACE1, 0, pool, "installing hooks");
@@ -259,9 +235,8 @@ static const char *val_H2_PUSH(apr_pool_
 {
     if (ctx) {
         if (r) {
-            h2_task *task = h2_ctx_get_task(ctx);
-            if (task) {
-                h2_stream *stream = h2_mplx_stream_get(task->mplx, task->stream_id);
+            if (ctx->task) {
+                h2_stream *stream = h2_mplx_stream_get(ctx->task->mplx, ctx->task->stream_id);
                 if (stream && stream->push_policy != H2_PUSH_NONE) {
                     return "on";
                 }
@@ -272,8 +247,7 @@ static const char *val_H2_PUSH(apr_pool_
         }
     }
     else if (s) {
-        const h2_config *cfg = h2_config_sget(s);
-        if (cfg && h2_config_geti(cfg, H2_CONF_PUSH)) {
+        if (h2_config_geti(r, s, H2_CONF_PUSH)) {
             return "on";
         }
     }
@@ -284,8 +258,7 @@ static const char *val_H2_PUSHED(apr_poo
                                  conn_rec *c, request_rec *r, h2_ctx *ctx)
 {
     if (ctx) {
-        h2_task *task = h2_ctx_get_task(ctx);
-        if (task && !H2_STREAM_CLIENT_INITIATED(task->stream_id)) {
+        if (ctx->task && !H2_STREAM_CLIENT_INITIATED(ctx->task->stream_id)) {
             return "PUSHED";
         }
     }
@@ -296,9 +269,8 @@ static const char *val_H2_PUSHED_ON(apr_
                                     conn_rec *c, request_rec *r, h2_ctx *ctx)
 {
     if (ctx) {
-        h2_task *task = h2_ctx_get_task(ctx);
-        if (task && !H2_STREAM_CLIENT_INITIATED(task->stream_id)) {
-            h2_stream *stream = h2_mplx_stream_get(task->mplx, task->stream_id);
+        if (ctx->task && !H2_STREAM_CLIENT_INITIATED(ctx->task->stream_id)) {
+            h2_stream *stream = h2_mplx_stream_get(ctx->task->mplx, ctx->task->stream_id);
             if (stream) {
                 return apr_itoa(p, stream->initiated_on);
             }
@@ -311,9 +283,8 @@ static const char *val_H2_STREAM_TAG(apr
                                      conn_rec *c, request_rec *r, h2_ctx *ctx)
 {
     if (ctx) {
-        h2_task *task = h2_ctx_get_task(ctx);
-        if (task) {
-            return task->id;
+        if (ctx->task) {
+            return ctx->task->id;
         }
     }
     return "";
@@ -365,7 +336,7 @@ static char *http2_var_lookup(apr_pool_t
     for (i = 0; i < H2_ALEN(H2_VARS); ++i) {
         h2_var_def *vdef = &H2_VARS[i];
         if (!strcmp(vdef->name, name)) {
-            h2_ctx *ctx = (r? h2_ctx_rget(r) : 
+            h2_ctx *ctx = (r? h2_ctx_get(c, 0) :
                            h2_ctx_get(c->master? c->master : c, 0));
             return (char *)vdef->lookup(p, s, c, r, ctx);
         }
@@ -376,7 +347,7 @@ static char *http2_var_lookup(apr_pool_t
 static int h2_h2_fixups(request_rec *r)
 {
     if (r->connection->master) {
-        h2_ctx *ctx = h2_ctx_rget(r);
+        h2_ctx *ctx = h2_ctx_get(r->connection, 0);
         int i;
         
         for (i = 0; ctx && i < H2_ALEN(H2_VARS); ++i) {
Index: httpd-2.4.23/modules/http2/mod_http2.dep
===================================================================
--- httpd-2.4.23.orig/modules/http2/mod_http2.dep	2019-04-02 13:39:34.080792611 +0200
+++ httpd-2.4.23/modules/http2/mod_http2.dep	2019-04-02 13:39:34.264793530 +0200
@@ -694,7 +694,6 @@
 	".\h2_ctx.h"\
 	".\h2_h2.h"\
 	".\h2_mplx.h"\
-	".\h2_ngn_shed.h"\
 	".\h2_private.h"\
 	".\h2_request.h"\
 	".\h2_stream.h"\
@@ -754,7 +753,6 @@
 	".\h2_ctx.h"\
 	".\h2_h2.h"\
 	".\h2_mplx.h"\
-	".\h2_ngn_shed.h"\
 	".\h2_private.h"\
 	".\h2_request.h"\
 	".\h2_task.h"\
Index: httpd-2.4.23/modules/http2/mod_http2.dsp
===================================================================
--- httpd-2.4.23.orig/modules/http2/mod_http2.dsp	2019-04-02 13:39:34.080792611 +0200
+++ httpd-2.4.23/modules/http2/mod_http2.dsp	2019-04-02 13:39:34.264793530 +0200
@@ -145,10 +145,6 @@ SOURCE=./h2_mplx.c
 # End Source File
 # Begin Source File
 
-SOURCE=./h2_ngn_shed.c
-# End Source File
-# Begin Source File
-
 SOURCE=./h2_push.c
 # End Source File
 # Begin Source File
Index: httpd-2.4.23/modules/http2/mod_http2.h
===================================================================
--- httpd-2.4.23.orig/modules/http2/mod_http2.h	2019-04-02 13:39:34.196793190 +0200
+++ httpd-2.4.23/modules/http2/mod_http2.h	2019-04-02 13:42:32.653683156 +0200
@@ -29,22 +29,20 @@ APR_DECLARE_OPTIONAL_FN(int,
 
 
 /*******************************************************************************
- * HTTP/2 request engines
+ * START HTTP/2 request engines (DEPRECATED)
  ******************************************************************************/
+
+/* The following functions were introduced for the experimental mod_proxy_http2
+ * support, but have been abandoned since.
+ * They are still declared here for backward compatibiliy, in case someone
+ * tries to build an old mod_proxy_http2 against it, but will disappear
+ * completely sometime in the future.
+ */
  
 struct apr_thread_cond_t;
-
 typedef struct h2_req_engine h2_req_engine;
-
 typedef void http2_output_consumed(void *ctx, conn_rec *c, apr_off_t consumed);
 
-/**
- * Initialize a h2_req_engine. The structure will be passed in but
- * only the name and master are set. The function should initialize
- * all fields.
- * @param engine the allocated, partially filled structure
- * @param r      the first request to process, or NULL
- */
 typedef apr_status_t http2_req_engine_init(h2_req_engine *engine, 
                                            const char *id, 
                                            const char *type,
@@ -54,35 +52,11 @@ typedef apr_status_t http2_req_engine_in
                                            http2_output_consumed **pconsumed,
                                            void **pbaton);
 
-/**
- * Push a request to an engine with the specified name for further processing.
- * If no such engine is available, einit is not NULL, einit is called 
- * with a new engine record and the caller is responsible for running the
- * new engine instance.
- * @param engine_type the type of the engine to add the request to
- * @param r           the request to push to an engine for processing
- * @param einit       an optional initialization callback for a new engine 
- *                    of the requested type, should no instance be available.
- *                    By passing a non-NULL callback, the caller is willing
- *                    to init and run a new engine itself.
- * @return APR_SUCCESS iff slave was successfully added to an engine
- */
 APR_DECLARE_OPTIONAL_FN(apr_status_t, 
                         http2_req_engine_push, (const char *engine_type, 
                                                 request_rec *r,
                                                 http2_req_engine_init *einit));
 
-/**
- * Get a new request for processing in this engine.
- * @param engine      the engine which is done processing the slave
- * @param block       if call should block waiting for request to come
- * @param capacity    how many parallel requests are acceptable
- * @param pr          the request that needs processing or NULL
- * @return APR_SUCCESS if new request was assigned
- *         APR_EAGAIN  if no new request is available
- *         APR_EOF          if engine may shut down, as no more request will be scheduled
- *         APR_ECONNABORTED if the engine needs to shut down immediately
- */
 APR_DECLARE_OPTIONAL_FN(apr_status_t, 
                         http2_req_engine_pull, (h2_req_engine *engine, 
                                                 apr_read_type_e block,
@@ -97,4 +71,8 @@ APR_DECLARE_OPTIONAL_FN(void,
                         http2_get_num_workers, (server_rec *s,
                                                 int *minw, int *max));
 
+/*******************************************************************************
+ * END HTTP/2 request engines (DEPRECATED)
+ ******************************************************************************/
+
 #endif
Index: httpd-2.4.23/modules/http2/mod_http2.mak
===================================================================
--- httpd-2.4.23.orig/modules/http2/mod_http2.mak	2019-04-02 13:39:34.080792611 +0200
+++ httpd-2.4.23/modules/http2/mod_http2.mak	2019-04-02 13:39:34.264793530 +0200
@@ -61,7 +61,6 @@ CLEAN :
 	-@erase "$(INTDIR)\h2_h2.obj"
 	-@erase "$(INTDIR)\h2_headers.obj"
 	-@erase "$(INTDIR)\h2_mplx.obj"
-	-@erase "$(INTDIR)\h2_ngn_shed.obj"
 	-@erase "$(INTDIR)\h2_push.obj"
 	-@erase "$(INTDIR)\h2_request.obj"
 	-@erase "$(INTDIR)\h2_session.obj"
@@ -138,7 +137,6 @@ LINK32_OBJS= \
 	"$(INTDIR)\h2_h2.obj" \
 	"$(INTDIR)\h2_headers.obj" \
 	"$(INTDIR)\h2_mplx.obj" \
-	"$(INTDIR)\h2_ngn_shed.obj" \
 	"$(INTDIR)\h2_push.obj" \
 	"$(INTDIR)\h2_request.obj" \
 	"$(INTDIR)\h2_session.obj" \
@@ -207,7 +205,6 @@ CLEAN :
 	-@erase "$(INTDIR)\h2_h2.obj"
 	-@erase "$(INTDIR)\h2_headers.obj"
 	-@erase "$(INTDIR)\h2_mplx.obj"
-	-@erase "$(INTDIR)\h2_ngn_shed.obj"
 	-@erase "$(INTDIR)\h2_push.obj"
 	-@erase "$(INTDIR)\h2_request.obj"
 	-@erase "$(INTDIR)\h2_session.obj"
@@ -284,7 +281,6 @@ LINK32_OBJS= \
 	"$(INTDIR)\h2_h2.obj" \
 	"$(INTDIR)\h2_headers.obj" \
 	"$(INTDIR)\h2_mplx.obj" \
-	"$(INTDIR)\h2_ngn_shed.obj" \
 	"$(INTDIR)\h2_push.obj" \
 	"$(INTDIR)\h2_request.obj" \
 	"$(INTDIR)\h2_session.obj" \
@@ -469,11 +465,6 @@ SOURCE=./h2_mplx.c
 "$(INTDIR)\h2_mplx.obj" : $(SOURCE) "$(INTDIR)"
 
 
-SOURCE=./h2_ngn_shed.c
-
-"$(INTDIR)\h2_ngn_shed.obj" : $(SOURCE) "$(INTDIR)"
-
-
 SOURCE=./h2_push.c
 
 "$(INTDIR)\h2_push.obj" : $(SOURCE) "$(INTDIR)"
Index: httpd-2.4.23/modules/http2/mod_proxy_http2.c
===================================================================
--- httpd-2.4.23.orig/modules/http2/mod_proxy_http2.c	2019-04-02 13:39:34.196793190 +0200
+++ httpd-2.4.23/modules/http2/mod_proxy_http2.c	2019-04-02 13:42:32.653683156 +0200
@@ -15,13 +15,14 @@
 
 #include <nghttp2/nghttp2.h>
 
+#include <ap_mmn.h>
 #include <httpd.h>
 #include <mod_proxy.h>
 #include "mod_http2.h"
 
 
 #include "mod_proxy_http2.h"
-#include "h2_request.h"
+#include "h2.h"
 #include "h2_proxy_util.h"
 #include "h2_version.h"
 #include "h2_proxy_session.h"
@@ -45,19 +46,12 @@ AP_DECLARE_MODULE(proxy_http2) = {
 
 /* Optional functions from mod_http2 */
 static int (*is_h2)(conn_rec *c);
-static apr_status_t (*req_engine_push)(const char *name, request_rec *r, 
-                                       http2_req_engine_init *einit);
-static apr_status_t (*req_engine_pull)(h2_req_engine *engine, 
-                                       apr_read_type_e block, 
-                                       int capacity, 
-                                       request_rec **pr);
-static void (*req_engine_done)(h2_req_engine *engine, conn_rec *r_conn,
-                               apr_status_t status);
-                                       
+
 typedef struct h2_proxy_ctx {
+    const char *id;
+    conn_rec *master;
     conn_rec *owner;
     apr_pool_t *pool;
-    request_rec *rbase;
     server_rec *server;
     const char *proxy_func;
     char server_portstr[32];
@@ -65,19 +59,16 @@ typedef struct h2_proxy_ctx {
     proxy_worker *worker;
     proxy_server_conf *conf;
     
-    h2_req_engine *engine;
-    const char *engine_id;
-    const char *engine_type;
-    apr_pool_t *engine_pool;    
     apr_size_t req_buffer_size;
-    h2_proxy_fifo *requests;
     int capacity;
     
-    unsigned standalone : 1;
     unsigned is_ssl : 1;
     unsigned flushall : 1;
     
-    apr_status_t r_status;     /* status of our first request work */
+    request_rec *r;            /* the request processed in this ctx */
+    apr_status_t r_status;     /* status of request work */
+    int r_done;                /* request was processed, not necessarily successfully */
+    int r_may_retry;           /* request may be retried */
     h2_proxy_session *session; /* current http2 session against backend */
 } h2_proxy_ctx;
 
@@ -103,16 +94,6 @@ static int h2_proxy_post_config(apr_pool
                  MOD_HTTP2_VERSION, ngh2? ngh2->version_str : "unknown");
     
     is_h2 = APR_RETRIEVE_OPTIONAL_FN(http2_is_h2);
-    req_engine_push = APR_RETRIEVE_OPTIONAL_FN(http2_req_engine_push);
-    req_engine_pull = APR_RETRIEVE_OPTIONAL_FN(http2_req_engine_pull);
-    req_engine_done = APR_RETRIEVE_OPTIONAL_FN(http2_req_engine_done);
-    
-    /* we need all of them */
-    if (!req_engine_push || !req_engine_pull || !req_engine_done) {
-        req_engine_push = NULL;
-        req_engine_pull = NULL;
-        req_engine_done = NULL;
-    }
     
     return status;
 }
@@ -203,45 +184,6 @@ static int proxy_http2_canon(request_rec
     return OK;
 }
 
-static void out_consumed(void *baton, conn_rec *c, apr_off_t bytes)
-{
-    h2_proxy_ctx *ctx = baton;
-    
-    if (ctx->session) {
-        h2_proxy_session_update_window(ctx->session, c, bytes);
-    }
-}
-
-static apr_status_t proxy_engine_init(h2_req_engine *engine, 
-                                        const char *id, 
-                                        const char *type,
-                                        apr_pool_t *pool, 
-                                        apr_size_t req_buffer_size,
-                                        request_rec *r,
-                                        http2_output_consumed **pconsumed,
-                                        void **pctx)
-{
-    h2_proxy_ctx *ctx = ap_get_module_config(r->connection->conn_config, 
-                                             &proxy_http2_module);
-    if (!ctx) {
-        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(03368)
-                      "h2_proxy_session, engine init, no ctx found");
-        return APR_ENOTIMPL;
-    }
-    
-    ctx->pool = pool;
-    ctx->engine = engine;
-    ctx->engine_id = id;
-    ctx->engine_type = type;
-    ctx->engine_pool = pool;
-    ctx->req_buffer_size = req_buffer_size;
-    ctx->capacity = H2MIN(100, h2_proxy_fifo_capacity(ctx->requests));
-    
-    *pconsumed = out_consumed;
-    *pctx = ctx;
-    return APR_SUCCESS;
-}
-
 static apr_status_t add_request(h2_proxy_session *session, request_rec *r)
 {
     h2_proxy_ctx *ctx = session->user_data;
@@ -251,7 +193,7 @@ static apr_status_t add_request(h2_proxy
     url = apr_table_get(r->notes, H2_PROXY_REQ_URL_NOTE);
     apr_table_setn(r->notes, "proxy-source-port", apr_psprintf(r->pool, "%hu",
                    ctx->p_conn->connection->local_addr->port));
-    status = h2_proxy_session_submit(session, url, r, ctx->standalone);
+    status = h2_proxy_session_submit(session, url, r, 1);
     if (status != APR_SUCCESS) {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, status, r->connection, APLOGNO(03351)
                       "pass request body failed to %pI (%s) from %s (%s)",
@@ -265,43 +207,15 @@ static apr_status_t add_request(h2_proxy
 static void request_done(h2_proxy_ctx *ctx, request_rec *r,
                          apr_status_t status, int touched)
 {   
-    const char *task_id = apr_table_get(r->connection->notes, H2_TASK_ID_NOTE);
-
-    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, r->connection, 
-                  "h2_proxy_session(%s): request done %s, touched=%d",
-                  ctx->engine_id, task_id, touched);
-    if (status != APR_SUCCESS) {
-        if (!touched) {
-            /* untouched request, need rescheduling */
-            status = h2_proxy_fifo_push(ctx->requests, r);
-            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, r->connection, 
-                          APLOGNO(03369)
-                          "h2_proxy_session(%s): rescheduled request %s",
-                          ctx->engine_id, task_id);
-            return;
-        }
-        else {
-            const char *uri;
-            uri = apr_uri_unparse(r->pool, &r->parsed_uri, 0);
-            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, r->connection, 
-                          APLOGNO(03471) "h2_proxy_session(%s): request %s -> %s "
-                          "not complete, cannot repeat", 
-                          ctx->engine_id, task_id, uri);
-        }
-    }
-    
-    if (r == ctx->rbase) {
+    if (r == ctx->r) {
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, r->connection,
+                      "h2_proxy_session(%s): request done, touched=%d",
+                      ctx->id, touched);
+        ctx->r_done = 1;
+        if (touched) ctx->r_may_retry = 0;
         ctx->r_status = ((status == APR_SUCCESS)? APR_SUCCESS
                          : HTTP_SERVICE_UNAVAILABLE);
     }
-    
-    if (req_engine_done && ctx->engine) {
-        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, r->connection, 
-                      APLOGNO(03370)
-                      "h2_proxy_session(%s): finished request %s",
-                      ctx->engine_id, task_id);
-        req_engine_done(ctx->engine, r->connection, status);
-    }
 }    
 
 static void session_req_done(h2_proxy_session *session, request_rec *r,
@@ -310,43 +224,15 @@ static void session_req_done(h2_proxy_se
     request_done(session->user_data, r, status, touched);
 }
 
-static apr_status_t next_request(h2_proxy_ctx *ctx, int before_leave)
-{
-    if (h2_proxy_fifo_count(ctx->requests) > 0) {
-        return APR_SUCCESS;
-    }
-    else if (req_engine_pull && ctx->engine) {
-        apr_status_t status;
-        request_rec *r = NULL;
-        
-        status = req_engine_pull(ctx->engine, before_leave? 
-                                 APR_BLOCK_READ: APR_NONBLOCK_READ, 
-                                 ctx->capacity, &r);
-        if (status == APR_SUCCESS && r) {
-            ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, ctx->owner, 
-                          "h2_proxy_engine(%s): pulled request (%s) %s", 
-                          ctx->engine_id, 
-                          before_leave? "before leave" : "regular", 
-                          r->the_request);
-            h2_proxy_fifo_push(ctx->requests, r);
-        }
-        return APR_STATUS_IS_EAGAIN(status)? APR_SUCCESS : status;
-    }
-    return APR_EOF;
-}
-
-static apr_status_t proxy_engine_run(h2_proxy_ctx *ctx) {
+static apr_status_t ctx_run(h2_proxy_ctx *ctx) {
     apr_status_t status = OK;
     int h2_front;
-    request_rec *r;
     
     /* Step Four: Send the Request in a new HTTP/2 stream and
      * loop until we got the response or encounter errors.
      */
-    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctx->owner, 
-                  "eng(%s): setup session", ctx->engine_id);
     h2_front = is_h2? is_h2(ctx->owner) : 0;
-    ctx->session = h2_proxy_session_setup(ctx->engine_id, ctx->p_conn, ctx->conf,
+    ctx->session = h2_proxy_session_setup(ctx->id, ctx->p_conn, ctx->conf,
                                           h2_front, 30, 
                                           h2_proxy_log2((int)ctx->req_buffer_size), 
                                           session_req_done);
@@ -357,105 +243,45 @@ static apr_status_t proxy_engine_run(h2_
     }
     
     ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->owner, APLOGNO(03373)
-                  "eng(%s): run session %s", ctx->engine_id, ctx->session->id);
+                  "eng(%s): run session %s", ctx->id, ctx->session->id);
     ctx->session->user_data = ctx;
     
-    while (!ctx->owner->aborted) {
-        if (APR_SUCCESS == h2_proxy_fifo_try_pull(ctx->requests, (void**)&r)) {
-            add_request(ctx->session, r);
-        }
-        
+    ctx->r_done = 0;
+    add_request(ctx->session, ctx->r);
+
+    while (!ctx->master->aborted && !ctx->r_done) {
+
         status = h2_proxy_session_process(ctx->session);
-        
-        if (status == APR_SUCCESS) {
-            apr_status_t s2;
-            /* ongoing processing, call again */
-            if (ctx->session->remote_max_concurrent > 0
-                && ctx->session->remote_max_concurrent != ctx->capacity) {
-                ctx->capacity = H2MIN((int)ctx->session->remote_max_concurrent, 
-                                      h2_proxy_fifo_capacity(ctx->requests));
-            }
-            s2 = next_request(ctx, 0);
-            if (s2 == APR_ECONNABORTED) {
-                /* master connection gone */
-                ap_log_cerror(APLOG_MARK, APLOG_DEBUG, s2, ctx->owner, 
-                              APLOGNO(03374) "eng(%s): pull request", 
-                              ctx->engine_id);
-                /* give notice that we're leaving and cancel all ongoing
-                 * streams. */
-                next_request(ctx, 1); 
-                h2_proxy_session_cancel_all(ctx->session);
-                h2_proxy_session_process(ctx->session);
-                status = ctx->r_status = APR_SUCCESS;
-                break;
-            }
-            if ((h2_proxy_fifo_count(ctx->requests) == 0) 
-                && h2_proxy_ihash_empty(ctx->session->streams)) {
-                break;
-            }
-        }
-        else {
-            /* end of processing, maybe error */
+        if (status != APR_SUCCESS) {
+            /* Encountered an error during session processing */
             ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, ctx->owner, 
                           APLOGNO(03375) "eng(%s): end of session %s", 
-                          ctx->engine_id, ctx->session->id);
-            /*
-             * Any open stream of that session needs to
+                          ctx->id, ctx->session->id);
+            /* Any open stream of that session needs to
              * a) be reopened on the new session iff safe to do so
              * b) reported as done (failed) otherwise
              */
             h2_proxy_session_cleanup(ctx->session, session_req_done);
-            break;
+            goto out;
         }
     }
     
-    ctx->session->user_data = NULL;
-    ctx->session = NULL;
-    
-    return status;
-}
-
-static apr_status_t push_request_somewhere(h2_proxy_ctx *ctx, request_rec *r)
-{
-    conn_rec *c = ctx->owner;
-    const char *engine_type, *hostname;
-    
-    hostname = (ctx->p_conn->ssl_hostname? 
-                ctx->p_conn->ssl_hostname : ctx->p_conn->hostname);
-    engine_type = apr_psprintf(ctx->pool, "proxy_http2 %s%s", hostname, 
-                               ctx->server_portstr);
-    
-    if (c->master && req_engine_push && r && is_h2 && is_h2(c)) {
-        /* If we are have req_engine capabilities, push the handling of this
-         * request (e.g. slave connection) to a proxy_http2 engine which 
-         * uses the same backend. We may be called to create an engine 
-         * ourself. */
-        if (req_engine_push(engine_type, r, proxy_engine_init) == APR_SUCCESS) {
-            if (ctx->engine == NULL) {
-                /* request has been assigned to an engine in another thread */
-                return SUSPENDED;
-            }
+out:
+    if (ctx->master->aborted) {
+        /* master connection gone */
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, ctx->owner,
+                      APLOGNO(03374) "eng(%s): master connection gone", ctx->id);
+        /* cancel all ongoing requests */
+        h2_proxy_session_cancel_all(ctx->session);
+        h2_proxy_session_process(ctx->session);
+        if (!ctx->master->aborted) {
+            status = ctx->r_status = APR_SUCCESS;
         }
     }
     
-    if (!ctx->engine) {
-        /* No engine was available or has been initialized, handle this
-         * request just by ourself. */
-        ctx->engine_id = apr_psprintf(ctx->pool, "eng-proxy-%ld", c->id);
-        ctx->engine_type = engine_type;
-        ctx->engine_pool = ctx->pool;
-        ctx->req_buffer_size = (32*1024);
-        ctx->standalone = 1;
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, 
-                      "h2_proxy_http2(%ld): setup standalone engine for type %s", 
-                      c->id, engine_type);
-    }
-    else {
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, 
-                      "H2: hosting engine %s", ctx->engine_id);
-    }
-
-    return h2_proxy_fifo_push(ctx->requests, r);
+    ctx->session->user_data = NULL;
+    ctx->session = NULL;
+    return status;
 }
 
 static int proxy_http2_handler(request_rec *r, 
@@ -465,7 +291,7 @@ static int proxy_http2_handler(request_r
                                const char *proxyname,
                                apr_port_t proxyport)
 {
-    const char *proxy_func;
+    const char *proxy_func, *task_id;
     char *locurl = url, *u;
     apr_size_t slen;
     int is_ssl = 0;
@@ -497,29 +323,36 @@ static int proxy_http2_handler(request_r
         default:
             return DECLINED;
     }
+
+    task_id = apr_table_get(r->connection->notes, H2_TASK_ID_NOTE);
     
     ctx = apr_pcalloc(r->pool, sizeof(*ctx));
-    ctx->owner      = r->connection;
-    ctx->pool       = r->pool;
-    ctx->rbase      = r;
-    ctx->server     = r->server;
+    ctx->master = r->connection->master? r->connection->master : r->connection;
+    ctx->id = task_id? task_id : apr_psprintf(r->pool, "%ld", (long)ctx->master->id);
+    ctx->owner = r->connection;
+    ctx->pool = r->pool;
+    ctx->server = r->server;
     ctx->proxy_func = proxy_func;
-    ctx->is_ssl     = is_ssl;
-    ctx->worker     = worker;
-    ctx->conf       = conf;
-    ctx->flushall   = apr_table_get(r->subprocess_env, "proxy-flushall")? 1 : 0;
-    ctx->r_status   = HTTP_SERVICE_UNAVAILABLE;
-    
-    h2_proxy_fifo_set_create(&ctx->requests, ctx->pool, 100);
+    ctx->is_ssl = is_ssl;
+    ctx->worker = worker;
+    ctx->conf = conf;
+    ctx->flushall = apr_table_get(r->subprocess_env, "proxy-flushall")? 1 : 0;
+    ctx->req_buffer_size = (32*1024);
+    ctx->r = r;
+    ctx->r_status = status = HTTP_SERVICE_UNAVAILABLE;
+    ctx->r_done = 0;
+    ctx->r_may_retry =  1;
     
     ap_set_module_config(ctx->owner->conn_config, &proxy_http2_module, ctx);
 
     /* scheme says, this is for us. */
-    apr_table_setn(ctx->rbase->notes, H2_PROXY_REQ_URL_NOTE, url);
-    ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, ctx->rbase, 
+    apr_table_setn(ctx->r->notes, H2_PROXY_REQ_URL_NOTE, url);
+    ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, ctx->r,
                   "H2: serving URL %s", url);
     
 run_connect:    
+    if (ctx->master->aborted) goto cleanup;
+
     /* Get a proxy_conn_rec from the worker, might be a new one, might
      * be one still open from another request, or it might fail if the
      * worker is stopped or in error. */
@@ -529,25 +362,11 @@ run_connect:
     }
 
     ctx->p_conn->is_ssl = ctx->is_ssl;
-    if (ctx->is_ssl && ctx->p_conn->connection) {
-        /* If there are some metadata on the connection (e.g. TLS alert),
-         * let mod_ssl detect them, and create a new connection below.
-         */ 
-        apr_bucket_brigade *tmp_bb;
-        tmp_bb = apr_brigade_create(ctx->rbase->pool, 
-                                    ctx->rbase->connection->bucket_alloc);
-        status = ap_get_brigade(ctx->p_conn->connection->input_filters, tmp_bb,
-                                AP_MODE_SPECULATIVE, APR_NONBLOCK_READ, 1);
-        if (status != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(status)) {
-            ctx->p_conn->close = 1;
-        }
-        apr_brigade_cleanup(tmp_bb);
-    }   
 
     /* Step One: Determine the URL to connect to (might be a proxy),
      * initialize the backend accordingly and determine the server 
      * port string we can expect in responses. */
-    if ((status = ap_proxy_determine_connection(ctx->pool, ctx->rbase, conf, worker, 
+    if ((status = ap_proxy_determine_connection(ctx->pool, ctx->r, conf, worker,
                                                 ctx->p_conn, &uri, &locurl, 
                                                 proxyname, proxyport, 
                                                 ctx->server_portstr,
@@ -555,17 +374,6 @@ run_connect:
         goto cleanup;
     }
     
-    /* If we are not already hosting an engine, try to push the request 
-     * to an already existing engine or host a new engine here. */
-    if (r && !ctx->engine) {
-        ctx->r_status = push_request_somewhere(ctx, r);
-        r = NULL;
-        if (ctx->r_status == SUSPENDED) {
-            /* request was pushed to another thread, leave processing here */
-            goto cleanup;
-        }
-    }
-    
     /* Step Two: Make the Connection (or check that an already existing
      * socket is still usable). On success, we have a socket connected to
      * backend->hostname. */
@@ -574,70 +382,58 @@ run_connect:
         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->owner, APLOGNO(03352)
                       "H2: failed to make connection to backend: %s",
                       ctx->p_conn->hostname);
-        goto reconnect;
+        goto cleanup;
     }
     
     /* Step Three: Create conn_rec for the socket we have open now. */
     if (!ctx->p_conn->connection) {
-        status = ap_proxy_connection_create_ex(ctx->proxy_func,
-                                               ctx->p_conn, ctx->rbase);
+        status = ap_proxy_connection_create_ex(ctx->proxy_func, ctx->p_conn, ctx->r);
         if (status != OK) {
             ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, ctx->owner, APLOGNO(03353)
                           "setup new connection: is_ssl=%d %s %s %s", 
                           ctx->p_conn->is_ssl, ctx->p_conn->ssl_hostname, 
                           locurl, ctx->p_conn->hostname);
-            goto reconnect;
+            ctx->r_status = status;
+            goto cleanup;
         }
         
-        if (!ctx->p_conn->data) {
-            /* New conection: set a note on the connection what CN is
-             * requested and what protocol we want */
+        if (!ctx->p_conn->data && ctx->is_ssl) {
+            /* New SSL connection: set a note on the connection about what
+             * protocol we want.
+             */
+            apr_table_setn(ctx->p_conn->connection->notes,
+                           "proxy-request-alpn-protos", "h2");
             if (ctx->p_conn->ssl_hostname) {
-                ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, ctx->owner, 
+                ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctx->owner,
                               "set SNI to %s for (%s)", 
                               ctx->p_conn->ssl_hostname, 
                               ctx->p_conn->hostname);
                 apr_table_setn(ctx->p_conn->connection->notes,
                                "proxy-request-hostname", ctx->p_conn->ssl_hostname);
             }
-            if (ctx->is_ssl) {
-                apr_table_setn(ctx->p_conn->connection->notes,
-                               "proxy-request-alpn-protos", "h2");
-            }
         }
     }
 
-run_session:
-    status = proxy_engine_run(ctx);
-    if (status == APR_SUCCESS) {
-        /* session and connection still ok */
-        if (next_request(ctx, 1) == APR_SUCCESS) {
-            /* more requests, run again */
-            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->owner, APLOGNO(03376)
-                          "run_session, again");
-            goto run_session;
-        }
-        /* done */
-        ctx->engine = NULL;
-    }
+    if (ctx->master->aborted) goto cleanup;
+    status = ctx_run(ctx);
 
-reconnect:
-    if (next_request(ctx, 1) == APR_SUCCESS) {
-        /* Still more to do, tear down old conn and start over */
+    if (ctx->r_status != APR_SUCCESS && ctx->r_may_retry && !ctx->master->aborted) {
+        /* Not successfully processed, but may retry, tear down old conn and start over */
         if (ctx->p_conn) {
             ctx->p_conn->close = 1;
-            /*only in trunk so far */
-            /*proxy_run_detach_backend(r, ctx->p_conn);*/
+#if AP_MODULE_MAGIC_AT_LEAST(20140207, 2)
+            proxy_run_detach_backend(r, ctx->p_conn);
+#endif
             ap_proxy_release_connection(ctx->proxy_func, ctx->p_conn, ctx->server);
             ctx->p_conn = NULL;
         }
         ++reconnects;
-        if (reconnects < 5 && !ctx->owner->aborted) {
+        if (reconnects < 5) {
             goto run_connect;
         } 
         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->owner, APLOGNO(10023)
-                      "giving up after %d reconnects, %d requests todo",
-                      reconnects, h2_proxy_fifo_count(ctx->requests));
+                      "giving up after %d reconnects, request-done=%d",
+                      reconnects, ctx->r_done);
     }
     
 cleanup:
@@ -646,17 +442,13 @@ cleanup:
             /* close socket when errors happened or session shut down (EOF) */
             ctx->p_conn->close = 1;
         }
-        /*only in trunk so far */
-        /*proxy_run_detach_backend(ctx->rbase, ctx->p_conn);*/
+#if AP_MODULE_MAGIC_AT_LEAST(20140207, 2)
+        proxy_run_detach_backend(ctx->r, ctx->p_conn);
+#endif
         ap_proxy_release_connection(ctx->proxy_func, ctx->p_conn, ctx->server);
         ctx->p_conn = NULL;
     }
 
-    /* Any requests will still have need to fail */
-    while (APR_SUCCESS == h2_proxy_fifo_try_pull(ctx->requests, (void**)&r)) {
-        request_done(ctx, r, HTTP_SERVICE_UNAVAILABLE, 1);
-    }
-    
     ap_set_module_config(ctx->owner->conn_config, &proxy_http2_module, NULL);
     ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, ctx->owner, 
                   APLOGNO(03377) "leaving handler");
