diff -upr httpd-2.4.33/modules/http2/h2_config.c httpd-2.4.41/modules/http2/h2_config.c
--- httpd-2.4.33/modules/http2/h2_config.c	2019-08-22 09:53:22.105935133 +0200
+++ httpd-2.4.41/modules/http2/h2_config.c	2019-03-13 16:00:57.000000000 +0100
@@ -62,16 +62,16 @@ typedef struct h2_config {
     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
+    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 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 */
@@ -215,7 +215,7 @@ void *h2_config_create_dir(apr_pool_t *p
     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;
@@ -379,7 +379,7 @@ static h2_config *h2_config_sget(server_
 
 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,
+    h2_dir_config *cfg = (h2_dir_config *)ap_get_module_config(r->per_dir_config, 
                                                                &http2_module);
     ap_assert(cfg);
     return cfg;
@@ -451,7 +451,7 @@ static void h2_config_seti64(h2_dir_conf
 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;
@@ -461,7 +461,7 @@ static const h2_config *h2_config_get(co
             return ctx->config;
         }
     }
-
+    
     return h2_config_sget(c->base_server);
 }
 
@@ -510,11 +510,11 @@ apr_array_header_t *h2_config_push_list(
 {
     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);
+    sconf = h2_config_sget(r->server); 
     return sconf? sconf->push_list : NULL;
 }
 
@@ -522,11 +522,11 @@ apr_array_header_t *h2_config_alt_svcs(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);
+    sconf = h2_config_sget(r->server); 
     return sconf? sconf->alt_svcs : NULL;
 }
 
@@ -881,10 +881,10 @@ static const char *h2_conf_set_early_hin
     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,
+        ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, cmd->pool, 
                             "H2EarlyHints = %d on path %s", val, cmd->path);
     }
     return NULL;
@@ -893,7 +893,7 @@ static const char *h2_conf_set_early_hin
 static const char *h2_conf_set_padding(cmd_parms *cmd, void *dirconf, const char *value)
 {
     int val;
-
+    
     val = (int)apr_atoi64(value);
     if (val < 0) {
         return "number of bits must be >= 0";
@@ -911,7 +911,7 @@ void h2_get_num_workers(server_rec *s, i
     int threads_per_child = 0;
 
     *minw = h2_config_sgeti(s, H2_CONF_MIN_WORKERS);
-    *maxw = h2_config_sgeti(s, H2_CONF_MAX_WORKERS);
+    *maxw = h2_config_sgeti(s, H2_CONF_MAX_WORKERS);    
     ap_mpm_query(AP_MPMQ_MAX_THREADS, &threads_per_child);
 
     if (*minw <= 0) {
diff -upr httpd-2.4.33/modules/http2/h2_config.h httpd-2.4.41/modules/http2/h2_config.h
--- httpd-2.4.33/modules/http2/h2_config.h	2019-08-22 09:53:22.105935133 +0200
+++ httpd-2.4.41/modules/http2/h2_config.h	2019-03-13 16:00:57.000000000 +0100
@@ -66,21 +66,21 @@ extern const command_rec h2_cmds[];
 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);
 
-/**
+/** 
  * 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.
+ * if configured for the request location. 
  * Fallback to request server config otherwise.
  */
 int h2_config_rgeti(request_rec *r, h2_config_var_t var);
diff -upr httpd-2.4.33/modules/http2/h2_conn.c httpd-2.4.41/modules/http2/h2_conn.c
--- httpd-2.4.33/modules/http2/h2_conn.c	2019-08-22 09:53:22.193935648 +0200
+++ httpd-2.4.41/modules/http2/h2_conn.c	2019-08-01 10:18:03.000000000 +0200
@@ -188,7 +188,7 @@ apr_status_t h2_conn_setup(conn_rec *c,
         ctx = h2_ctx_get(c, 1);
         h2_ctx_session_set(ctx, session);
     }
-
+    
     return status;
 }
 
@@ -341,7 +341,7 @@ conn_rec *h2_slave_create(conn_rec *mast
         ap_set_module_config(c->conn_config, mpm, cfg);
     }
 
-    ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, c,
+    ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, c, 
                   "h2_slave(%s): created", c->log_id);
     return c;
 }
diff -upr httpd-2.4.33/modules/http2/h2_conn_io.c httpd-2.4.41/modules/http2/h2_conn_io.c
--- httpd-2.4.33/modules/http2/h2_conn_io.c	2019-08-22 09:53:22.105935133 +0200
+++ httpd-2.4.41/modules/http2/h2_conn_io.c	2019-03-13 16:00:57.000000000 +0100
@@ -50,7 +50,7 @@
  * should make optimizations at the layer that writes
  * to TLS easier.
  */
-#define WRITE_SIZE_MAX        (TLS_DATA_MAX)
+#define WRITE_SIZE_MAX        (TLS_DATA_MAX) 
 
 
 static void h2_conn_io_bb_log(conn_rec *c, int stream_id, int level, 
@@ -141,7 +141,7 @@ apr_status_t h2_conn_io_init(h2_conn_io
          * see https://issues.apache.org/jira/browse/TS-2503 
          */
         io->warmup_size    = h2_config_sgeti64(s, H2_CONF_TLS_WARMUP_SIZE);
-        io->cooldown_usecs = (h2_config_sgeti(s, H2_CONF_TLS_COOLDOWN_SECS)
+        io->cooldown_usecs = (h2_config_sgeti(s, H2_CONF_TLS_COOLDOWN_SECS) 
                               * APR_USEC_PER_SEC);
         io->write_size     = (io->cooldown_usecs > 0? 
                               WRITE_SIZE_INITIAL : WRITE_SIZE_MAX); 
diff -upr httpd-2.4.33/modules/http2/h2_filter.c httpd-2.4.41/modules/http2/h2_filter.c
--- httpd-2.4.33/modules/http2/h2_filter.c	2019-08-22 09:53:22.193935648 +0200
+++ httpd-2.4.41/modules/http2/h2_filter.c	2019-08-01 10:18:03.000000000 +0200
@@ -436,7 +436,7 @@ static apr_status_t h2_status_insert(h2_
     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;
@@ -450,7 +450,7 @@ static apr_status_t h2_status_insert(h2_
     
     bb = apr_brigade_create(stream->pool, c->bucket_alloc);
     
-    connFlowIn = nghttp2_session_get_effective_local_window_size(s->ngh2);
+    connFlowIn = nghttp2_session_get_effective_local_window_size(s->ngh2); 
     connFlowOut = nghttp2_session_get_remote_window_size(s->ngh2);
      
     bbout(bb, "{\n");
diff -upr httpd-2.4.33/modules/http2/h2.h httpd-2.4.41/modules/http2/h2.h
--- httpd-2.4.33/modules/http2/h2.h	2019-08-22 09:53:22.109935157 +0200
+++ httpd-2.4.41/modules/http2/h2.h	2019-03-13 16:00:57.000000000 +0100
@@ -52,7 +52,7 @@ extern const char *H2_MAGIC_TOKEN;
 #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)
+#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
diff -upr httpd-2.4.33/modules/http2/h2_h2.c httpd-2.4.41/modules/http2/h2_h2.c
--- httpd-2.4.33/modules/http2/h2_h2.c	2019-08-22 09:53:22.109935157 +0200
+++ httpd-2.4.41/modules/http2/h2_h2.c	2019-03-13 16:00:57.000000000 +0100
@@ -463,7 +463,7 @@ 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, request_rec *r, 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);
 
@@ -584,7 +584,7 @@ int h2_h2_process_conn(conn_rec* c)
     
     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 (ctx && ctx->task) {
         /* our stream pseudo connection */
@@ -645,7 +645,7 @@ int h2_h2_process_conn(conn_rec* c)
 
     if (ctx) {
         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "process_conn");
-
+        
         if (!h2_ctx_get_session(c)) {
             status = h2_conn_setup(c, NULL, s);
             ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, c, "conn_setup");
@@ -688,7 +688,7 @@ static void check_push(request_rec *r, c
     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, push_list->nelts);
diff -upr httpd-2.4.33/modules/http2/h2_mplx.c httpd-2.4.41/modules/http2/h2_mplx.c
--- httpd-2.4.33/modules/http2/h2_mplx.c	2019-08-22 09:53:22.193935648 +0200
+++ httpd-2.4.41/modules/http2/h2_mplx.c	2019-08-01 10:18:03.000000000 +0200
@@ -147,7 +147,7 @@ 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, server_rec *s, apr_pool_t *parent,
+h2_mplx *h2_mplx_create(conn_rec *c, server_rec *s, apr_pool_t *parent, 
                         h2_workers *workers)
 {
     apr_status_t status = APR_SUCCESS;
@@ -373,7 +373,7 @@ 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]"),
+                      "[started=%d/done=%d]"), 
                       task->request->method, task->request->authority, 
                       task->request->path, task->worker_started, 
                       task->worker_done);
@@ -797,7 +797,7 @@ static void task_done(h2_mplx *m, h2_tas
             h2_task_redo(task);
             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"));
+                          H2_STRM_MSG(stream, "redo, added to q")); 
         }
         else {
             /* stream not cleaned up, stay around */
@@ -862,7 +862,6 @@ static int timed_out_busy_iter(void *dat
 {
     stream_iter_ctx *ctx = data;
     h2_stream *stream = val;
-    
     if (h2_task_has_started(stream->task) && !stream->task->worker_done
         && (ctx->now - stream->task->started_at) > stream->task->timeout) {
         /* timed out stream occupying a worker, found */
@@ -946,7 +945,7 @@ static apr_status_t unschedule_slow_task
      * that are repeatable. If none found, fail the connection.
      */
     while (APR_EAGAIN == (rv = assess_task_to_throttle(&task, m))) {
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c, 
                       "h2_mplx(%s): unschedule, resetting task for redo later",
                       task->id);
         task->redo = 1;
diff -upr httpd-2.4.33/modules/http2/h2_mplx.h httpd-2.4.41/modules/http2/h2_mplx.h
--- httpd-2.4.33/modules/http2/h2_mplx.h	2019-08-22 09:53:22.193935648 +0200
+++ httpd-2.4.41/modules/http2/h2_mplx.h	2019-08-01 10:18:03.000000000 +0200
@@ -105,7 +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, server_rec *s, apr_pool_t *master,
+h2_mplx *h2_mplx_create(conn_rec *c, server_rec *s, apr_pool_t *master, 
                         struct h2_workers *workers);
 
 /**
Only in httpd-2.4.33/modules/http2/: h2_ngn_shed.c
Only in httpd-2.4.33/modules/http2/: h2_ngn_shed.h
diff -upr httpd-2.4.33/modules/http2/h2_proxy_session.c httpd-2.4.41/modules/http2/h2_proxy_session.c
--- httpd-2.4.33/modules/http2/h2_proxy_session.c	2019-08-22 09:53:22.193935648 +0200
+++ httpd-2.4.41/modules/http2/h2_proxy_session.c	2019-08-01 10:18:03.000000000 +0200
@@ -45,6 +45,7 @@ typedef struct h2_proxy_stream {
     unsigned int suspended : 1;
     unsigned int waiting_on_100 : 1;
     unsigned int waiting_on_ping : 1;
+    unsigned int headers_ended : 1;
     uint32_t error_code;
 
     apr_bucket_brigade *input;
@@ -61,6 +62,7 @@ static void dispatch_event(h2_proxy_sess
 static void ping_arrived(h2_proxy_session *session);
 static apr_status_t check_suspended(h2_proxy_session *session);
 static void stream_resume(h2_proxy_stream *stream);
+static apr_status_t submit_trailers(h2_proxy_stream *stream);
 
 
 static apr_status_t proxy_session_pre_close(void *theconn)
@@ -241,7 +243,8 @@ static int add_header(void *table, const
     return 1;
 }
 
-static void process_proxy_header(h2_proxy_stream *stream, const char *n, const char *v)
+static void process_proxy_header(apr_table_t *headers, h2_proxy_stream *stream, 
+                                 const char *n, const char *v)
 {
     static const struct {
         const char *name;
@@ -262,20 +265,18 @@ static void process_proxy_header(h2_prox
     if (!dconf->preserve_host) {
         for (i = 0; transform_hdrs[i].name; ++i) {
             if (!ap_cstr_casecmp(transform_hdrs[i].name, n)) {
-                apr_table_add(r->headers_out, n,
-                              (*transform_hdrs[i].func)(r, dconf, v));
+                apr_table_add(headers, n, (*transform_hdrs[i].func)(r, dconf, v));
                 return;
             }
         }
         if (!ap_cstr_casecmp("Link", n)) {
             dconf = ap_get_module_config(r->per_dir_config, &proxy_module);
-            apr_table_add(r->headers_out, n,
-                          h2_proxy_link_reverse_map(r, dconf, 
-                                                    stream->real_server_uri, stream->p_server_uri, v));
+            apr_table_add(headers, n, h2_proxy_link_reverse_map(r, dconf, 
+                            stream->real_server_uri, stream->p_server_uri, v));
             return;
         }
     }
-    apr_table_add(r->headers_out, n, v);
+    apr_table_add(headers, n, v);
 }
 
 static apr_status_t h2_proxy_stream_add_header_out(h2_proxy_stream *stream,
@@ -299,8 +300,13 @@ static apr_status_t h2_proxy_stream_add_
         return APR_SUCCESS;
     }
     
+    ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, stream->session->c, 
+                  "h2_proxy_stream(%s-%d): on_header %s: %s", 
+                  stream->session->id, stream->id, n, v);
     if (!h2_proxy_res_ignore_header(n, nlen)) {
         char *hname, *hvalue;
+        apr_table_t *headers = (stream->headers_ended? 
+                               stream->r->trailers_out : stream->r->headers_out);
     
         hname = apr_pstrndup(stream->pool, n, nlen);
         h2_proxy_util_camel_case_header(hname, nlen);
@@ -309,7 +315,7 @@ static apr_status_t h2_proxy_stream_add_
         ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, stream->session->c, 
                       "h2_proxy_stream(%s-%d): got header %s: %s", 
                       stream->session->id, stream->id, hname, hvalue);
-        process_proxy_header(stream, hname, hvalue);
+        process_proxy_header(headers, stream, hname, hvalue);
     }
     return APR_SUCCESS;
 }
@@ -374,6 +380,7 @@ static void h2_proxy_stream_end_headers_
                                       server_name, portstr)
                        );
     }
+    if (r->status >= 200) stream->headers_ended = 1;
     
     if (APLOGrtrace2(stream->r)) {
         ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, stream->r, 
@@ -487,8 +494,8 @@ static ssize_t stream_request_data(nghtt
     stream = nghttp2_session_get_stream_user_data(ngh2, stream_id);
     if (!stream) {
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(03361)
-                     "h2_proxy_stream(%s): data_read, stream %d not found", 
-                     stream->session->id, stream_id);
+                     "h2_proxy_stream(NULL): data_read, stream %d not found", 
+                     stream_id);
         return NGHTTP2_ERR_CALLBACK_FAILURE;
     }
     
@@ -545,11 +552,16 @@ static ssize_t stream_request_data(nghtt
         }
 
         stream->data_sent += readlen;
-        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, stream->r, APLOGNO(10179) 
+        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, stream->r, APLOGNO(03468) 
                       "h2_proxy_stream(%d): request DATA %ld, %ld"
-                      " total, flags=%d", 
-                      stream->id, (long)readlen, (long)stream->data_sent,
+                      " total, flags=%d", stream->id, (long)readlen, (long)stream->data_sent,
                       (int)*data_flags);
+        if ((*data_flags & NGHTTP2_DATA_FLAG_EOF) && !apr_is_empty_table(stream->r->trailers_in)) {
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, stream->r, APLOGNO(10179) 
+                          "h2_proxy_stream(%d): submit trailers", stream->id);
+            *data_flags |= NGHTTP2_DATA_FLAG_NO_END_STREAM;
+            submit_trailers(stream);
+        } 
         return readlen;
     }
     else if (APR_STATUS_IS_EAGAIN(status)) {
@@ -736,6 +748,8 @@ static apr_status_t open_stream(h2_proxy
     stream->real_server_uri = apr_psprintf(stream->pool, "%s://%s", scheme, authority); 
     stream->p_server_uri = apr_psprintf(stream->pool, "%s://%s", puri.scheme, authority); 
     path = apr_uri_unparse(stream->pool, &puri, APR_URI_UNP_OMITSITEPART);
+
+
     h2_proxy_req_make(stream->req, stream->pool, r->method, scheme,
                 authority, path, r->headers_in);
 
@@ -822,6 +836,16 @@ static apr_status_t submit_stream(h2_pro
     return APR_EGENERAL;
 }
 
+static apr_status_t submit_trailers(h2_proxy_stream *stream)
+{
+    h2_proxy_ngheader *hd;
+    int rv;
+
+    hd = h2_proxy_util_nghd_make(stream->pool, stream->r->trailers_in);
+    rv = nghttp2_submit_trailer(stream->session->ngh2, stream->id, hd->nv, hd->nvlen);
+    return rv == 0? APR_SUCCESS: APR_EGENERAL;
+}
+
 static apr_status_t feed_brigade(h2_proxy_session *session, apr_bucket_brigade *bb)
 {
     apr_status_t status = APR_SUCCESS;
@@ -1419,7 +1443,7 @@ run_loop:
                 ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, session->c, 
                               APLOGNO(03365)
                               "h2_proxy_session(%s): WAIT read, timeout=%fms", 
-                              session->id, (float)session->wait_timeout/1000.0);
+                              session->id, session->wait_timeout/1000.0);
                 if (status == APR_SUCCESS) {
                     have_read = 1;
                     dispatch_event(session, H2_PROXYS_EV_DATA_READ, 0, NULL);
diff -upr httpd-2.4.33/modules/http2/h2_proxy_util.c httpd-2.4.41/modules/http2/h2_proxy_util.c
--- httpd-2.4.33/modules/http2/h2_proxy_util.c	2019-08-22 09:53:22.045934783 +0200
+++ httpd-2.4.41/modules/http2/h2_proxy_util.c	2019-07-02 13:11:08.000000000 +0200
@@ -452,6 +452,22 @@ h2_proxy_ngheader *h2_proxy_util_nghd_ma
     return ngh;
 }
 
+h2_proxy_ngheader *h2_proxy_util_nghd_make(apr_pool_t *p, apr_table_t *headers)
+{
+    
+    h2_proxy_ngheader *ngh;
+    size_t n;
+    
+    n = 0;
+    apr_table_do(count_header, &n, headers, NULL);
+    
+    ngh = apr_pcalloc(p, sizeof(h2_proxy_ngheader));
+    ngh->nv =  apr_pcalloc(p, n * sizeof(nghttp2_nv));
+    apr_table_do(add_table_header, ngh, headers, NULL);
+
+    return ngh;
+}
+
 /*******************************************************************************
  * header HTTP/1 <-> HTTP/2 conversions
  ******************************************************************************/
@@ -609,6 +625,7 @@ apr_status_t h2_proxy_req_make(h2_proxy_
                          apr_table_t *headers)
 {
     h1_ctx x;
+    const char *val;
 
     req->method    = method;
     req->scheme    = scheme;
@@ -623,6 +640,11 @@ apr_status_t h2_proxy_req_make(h2_proxy_
     x.pool = pool;
     x.headers = req->headers;
     apr_table_do(set_h1_header, &x, headers, NULL);
+    if ((val = apr_table_get(headers, "TE")) && ap_find_token(pool, val, "trailers")) {
+        /* client accepts trailers, forward this information */
+        apr_table_addn(req->headers, "TE", "trailers");
+    }
+    apr_table_setn(req->headers, "te", "trailers");
     return APR_SUCCESS;
 }
 
@@ -915,12 +937,12 @@ static size_t subst_str(link_ctx *ctx, i
     nlen = (int)strlen(ns);
     delta = nlen - olen;
     plen = ctx->slen + delta + 1;
-    p = apr_pcalloc(ctx->pool, plen);
+    p = apr_palloc(ctx->pool, plen);
     memcpy(p, ctx->s, start);
     memcpy(p + start, ns, nlen);
     strcpy(p + start + nlen, ctx->s + end);
     ctx->s = p;
-    ctx->slen = (int)strlen(p);
+    ctx->slen = plen - 1;   /* (int)strlen(p) */
     if (ctx->i >= end) {
         ctx->i += delta;
     }
diff -upr httpd-2.4.33/modules/http2/h2_proxy_util.h httpd-2.4.41/modules/http2/h2_proxy_util.h
--- httpd-2.4.33/modules/http2/h2_proxy_util.h	2018-02-10 16:46:12.000000000 +0100
+++ httpd-2.4.41/modules/http2/h2_proxy_util.h	2019-06-14 14:11:43.000000000 +0200
@@ -168,6 +168,8 @@ typedef struct h2_proxy_ngheader {
 h2_proxy_ngheader *h2_proxy_util_nghd_make_req(apr_pool_t *p, 
                                                const struct h2_proxy_request *req);
 
+h2_proxy_ngheader *h2_proxy_util_nghd_make(apr_pool_t *p, apr_table_t *headers);
+
 /*******************************************************************************
  * h2_proxy_request helpers
  ******************************************************************************/
diff -upr httpd-2.4.33/modules/http2/h2_request.c httpd-2.4.41/modules/http2/h2_request.c
--- httpd-2.4.33/modules/http2/h2_request.c	2019-08-22 09:53:22.109935157 +0200
+++ httpd-2.4.41/modules/http2/h2_request.c	2019-03-13 16:00:57.000000000 +0100
@@ -266,7 +266,7 @@ static request_rec *my_ap_create_request
 
 request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c)
 {
-    int access_status = HTTP_OK;
+    int access_status = HTTP_OK;    
     const char *rpath;
     const char *s;
 
diff -upr httpd-2.4.33/modules/http2/h2_session.c httpd-2.4.41/modules/http2/h2_session.c
--- httpd-2.4.33/modules/http2/h2_session.c	2019-08-22 09:53:22.197935671 +0200
+++ httpd-2.4.41/modules/http2/h2_session.c	2019-08-01 10:18:03.000000000 +0200
@@ -626,8 +626,8 @@ static int on_invalid_header_cb(nghttp2_
 }
 #endif
 
-static ssize_t select_padding_cb(nghttp2_session *ngh2,
-                                 const nghttp2_frame *frame,
+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;
@@ -635,23 +635,23 @@ static ssize_t select_padding_cb(nghttp2
     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.
+     * 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);
+        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
+        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,
+                          "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;
@@ -902,7 +902,7 @@ apr_status_t h2_session_create(h2_sessio
     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_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);
@@ -959,7 +959,7 @@ apr_status_t h2_session_create(h2_sessio
     }
     
     apr_pool_pre_cleanup_register(pool, c, session_pool_cleanup);
-
+        
     return APR_SUCCESS;
 }
 
diff -upr httpd-2.4.33/modules/http2/h2_session.h httpd-2.4.41/modules/http2/h2_session.h
--- httpd-2.4.33/modules/http2/h2_session.h	2019-08-22 09:53:22.109935157 +0200
+++ httpd-2.4.41/modules/http2/h2_session.h	2019-03-13 16:00:57.000000000 +0100
@@ -149,7 +149,7 @@ const char *h2_session_state_str(h2_sess
  * @return the created session
  */
 apr_status_t h2_session_create(h2_session **psession,
-                               conn_rec *c, request_rec *r, server_rec *,
+                               conn_rec *c, request_rec *r, server_rec *, 
                                struct h2_workers *workers);
 
 void h2_session_event(h2_session *session, h2_session_event_t ev, 
diff -upr httpd-2.4.33/modules/http2/h2_stream.c httpd-2.4.41/modules/http2/h2_stream.c
--- httpd-2.4.33/modules/http2/h2_stream.c	2019-08-22 09:53:22.197935671 +0200
+++ httpd-2.4.41/modules/http2/h2_stream.c	2019-08-08 23:23:29.000000000 +0200
@@ -783,7 +783,7 @@ apr_status_t h2_stream_end_headers(h2_st
         apr_table_do(table_check_val_len, &ctx, stream->request->headers, NULL);
         if (ctx.failed_key) {
             ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, stream->session->c,  
-                          H2_STRM_LOG(APLOGNO(), stream,"Request header exceeds "
+                          H2_STRM_LOG(APLOGNO(10190), stream,"Request header exceeds "
                                       "LimitRequestFieldSize: %.*s"),
                           (int)H2MIN(strlen(ctx.failed_key), 80), ctx.failed_key);
             set_error_response(stream, HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE);
@@ -894,7 +894,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 - H2_FRAME_HDR_LEN;
+        max_chunk = stream->session->io.write_size - H2_FRAME_HDR_LEN; 
     }
     requested = (*plen > 0)? H2MIN(*plen, max_chunk) : max_chunk;
     
diff -upr httpd-2.4.33/modules/http2/h2_switch.c httpd-2.4.41/modules/http2/h2_switch.c
--- httpd-2.4.33/modules/http2/h2_switch.c	2019-08-22 09:53:22.113935179 +0200
+++ httpd-2.4.41/modules/http2/h2_switch.c	2019-03-13 16:00:57.000000000 +0100
@@ -164,7 +164,7 @@ static int h2_protocol_switch(conn_rec *
             
             /* Ok, start an h2_conn on this one. */
             status = h2_conn_setup(c, r, s);
-
+            
             if (status != APR_SUCCESS) {
                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(03088)
                               "session setup");
diff -upr httpd-2.4.33/modules/http2/h2_task.h httpd-2.4.41/modules/http2/h2_task.h
--- httpd-2.4.33/modules/http2/h2_task.h	2019-08-22 09:53:22.197935671 +0200
+++ httpd-2.4.41/modules/http2/h2_task.h	2019-08-01 10:18:03.000000000 +0200
@@ -81,7 +81,7 @@ struct h2_task {
     unsigned int filters_set    : 1;
     unsigned int worker_started : 1; /* h2_worker started processing */
     unsigned int redo : 1;           /* was throttled, should be restarted later */
-
+    
     int worker_done;                 /* h2_worker finished */
     int done_done;                   /* task_done has been handled */
     
diff -upr httpd-2.4.33/modules/http2/mod_http2.c httpd-2.4.41/modules/http2/mod_http2.c
--- httpd-2.4.33/modules/http2/mod_http2.c	2019-08-22 09:53:22.113935179 +0200
+++ httpd-2.4.41/modules/http2/mod_http2.c	2019-03-13 16:00:57.000000000 +0100
@@ -337,7 +337,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_get(c, 0) :
+            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);
         }
diff -upr httpd-2.4.33/modules/http2/mod_http2.h httpd-2.4.41/modules/http2/mod_http2.h
--- httpd-2.4.33/modules/http2/mod_http2.h	2019-08-22 09:53:22.113935179 +0200
+++ httpd-2.4.41/modules/http2/mod_http2.h	2019-03-13 16:00:57.000000000 +0100
@@ -38,7 +38,7 @@ APR_DECLARE_OPTIONAL_FN(int,
  * 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;
diff -upr httpd-2.4.33/modules/http2/mod_proxy_http2.c httpd-2.4.41/modules/http2/mod_proxy_http2.c
--- httpd-2.4.33/modules/http2/mod_proxy_http2.c	2019-08-22 09:53:22.113935179 +0200
+++ httpd-2.4.41/modules/http2/mod_proxy_http2.c	2019-05-28 01:19:12.000000000 +0200
@@ -64,7 +64,6 @@ typedef struct h2_proxy_ctx {
     int capacity;
     
     unsigned is_ssl : 1;
-    unsigned flushall : 1;
     
     request_rec *r;            /* the request processed in this ctx */
     apr_status_t r_status;     /* status of request work */
@@ -209,7 +208,7 @@ static void request_done(h2_proxy_ctx *c
                          apr_status_t status, int touched)
 {   
     if (r == ctx->r) {
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, r->connection,
+        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;
@@ -249,9 +248,9 @@ static apr_status_t ctx_run(h2_proxy_ctx
     
     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) {
             /* Encountered an error during session processing */
@@ -270,7 +269,7 @@ static apr_status_t ctx_run(h2_proxy_ctx
 out:
     if (ctx->master->aborted) {
         /* master connection gone */
-        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, ctx->owner,
+        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);
@@ -337,7 +336,6 @@ static int proxy_http2_handler(request_r
     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;
@@ -348,7 +346,7 @@ static int proxy_http2_handler(request_r
 
     /* scheme says, this is for us. */
     apr_table_setn(ctx->r->notes, H2_PROXY_REQ_URL_NOTE, url);
-    ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, ctx->r,
+    ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, ctx->r, 
                   "H2: serving URL %s", url);
     
 run_connect:    
@@ -367,7 +365,7 @@ run_connect:
     /* 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->r, conf, worker,
+    if ((status = ap_proxy_determine_connection(ctx->pool, ctx->r, conf, worker, 
                                                 ctx->p_conn, &uri, &locurl, 
                                                 proxyname, proxyport, 
                                                 ctx->server_portstr,
@@ -387,32 +385,22 @@ run_connect:
     }
     
     /* 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->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);
-            ctx->r_status = status;
-            goto cleanup;
-        }
-        
-        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, 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);
-            }
-        }
+    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);
+        ctx->r_status = status;
+        goto cleanup;
+    }
+    
+    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->master->aborted) goto cleanup;
