]> granicus.if.org Git - apache/commitdiff
mod_http2: backport of 1.4.3
authorStefan Eissing <icing@apache.org>
Thu, 17 Mar 2016 16:54:05 +0000 (16:54 +0000)
committerStefan Eissing <icing@apache.org>
Thu, 17 Mar 2016 16:54:05 +0000 (16:54 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1735457 13f79535-47bb-0310-9956-ffa450edef68

14 files changed:
CHANGES
modules/http2/h2_conn.c
modules/http2/h2_conn.h
modules/http2/h2_mplx.c
modules/http2/h2_mplx.h
modules/http2/h2_ngn_shed.c
modules/http2/h2_task.c
modules/http2/h2_task.h
modules/http2/h2_task_input.c
modules/http2/h2_task_input.h
modules/http2/h2_task_output.c
modules/http2/h2_task_output.h
modules/http2/h2_util.c
modules/http2/h2_version.h

diff --git a/CHANGES b/CHANGES
index 12ed720e6fa4873d79eaa28d692137b0da167bd2..5263cafa5a8f45fb7baeb2e211cfadc069b8b133 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,9 @@
 
 Changes with Apache 2.4.19
 
+  *) mod_http2: slave connections are reused for several requests, improved
+     performance and better memory use. [Stefan Eissing]
+     
   *) mod_rewrite: Don't implicitly URL-escape the original query string
      when no substitution has changed it (like PR50447 but server context)
      [Evgeny Kotkov <evgeny.kotkov visualsvn.com>]
index 60e209492c4a6e0726f560109483c2b70a9dc99a..3b28c1f925a9ab03d0fcc379e9e1c85e513b637a 100644 (file)
@@ -239,7 +239,6 @@ apr_status_t h2_conn_pre_close(struct h2_ctx *ctx, conn_rec *c)
     return status;
 }
 
-
 conn_rec *h2_slave_create(conn_rec *master, apr_pool_t *parent,
                           apr_allocator_t *allocator)
 {
@@ -262,7 +261,7 @@ conn_rec *h2_slave_create(conn_rec *master, apr_pool_t *parent,
     apr_pool_create_ex(&pool, parent, NULL, allocator);
     apr_pool_tag(pool, "h2_slave_conn");
     apr_allocator_owner_set(allocator, pool);
-    
+
     c = (conn_rec *) apr_palloc(pool, sizeof(conn_rec));
     if (c == NULL) {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, master, 
@@ -324,3 +323,9 @@ void h2_slave_destroy(conn_rec *slave, apr_allocator_t **pallocator)
     }
     apr_pool_destroy(slave->pool);
 }
+
+apr_status_t h2_slave_run_pre_connection(conn_rec *slave, apr_socket_t *csd)
+{
+    return ap_run_pre_connection(slave, csd);
+}
+
index 023eecaaca075a708bb5603fa18bb3e6ccae0be9..e52fc8d69ef7ee918ae9db2ea4409e0c0475c803 100644 (file)
@@ -70,4 +70,7 @@ conn_rec *h2_slave_create(conn_rec *master, apr_pool_t *parent,
                           apr_allocator_t *allocator);
 void h2_slave_destroy(conn_rec *slave, apr_allocator_t **pallocator);
 
+apr_status_t h2_slave_run_pre_connection(conn_rec *slave, apr_socket_t *csd);
+void h2_slave_run_connection(conn_rec *slave);
+
 #endif /* defined(__mod_h2__h2_conn__) */
index 1284c432556be3955b4c9f212d380087404b4f39..1133807c33896862dbb77fd36845a81d8ff09646 100644 (file)
@@ -218,6 +218,8 @@ h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *parent,
         m->tx_handles_reserved = 0;
         m->tx_chunk_size = 4;
         
+        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);
@@ -278,8 +280,6 @@ static int io_out_consumed_signal(h2_mplx *m, h2_io *io)
 
 static void io_destroy(h2_mplx *m, h2_io *io, int events)
 {
-    apr_pool_t *pool;
-    
     /* cleanup any buffered input */
     h2_io_in_shutdown(io);
     if (events) {
@@ -299,23 +299,20 @@ static void io_destroy(h2_mplx *m, h2_io *io, int events)
     }
 
     if (io->task) {
-        if (m->spare_allocator) {
-            apr_allocator_destroy(m->spare_allocator);
-            m->spare_allocator = NULL;
-        }
-        
-        h2_slave_destroy(io->task->c, &m->spare_allocator);
+        conn_rec *slave = io->task->c;
+        h2_task_destroy(io->task);
         io->task = NULL;
+        
+        if (m->spare_slaves->nelts < m->spare_slaves->nalloc) {
+            APR_ARRAY_PUSH(m->spare_slaves, conn_rec*) = slave;
+        }
+        else {
+            h2_slave_destroy(slave, NULL);
+        }
     }
 
-    pool = io->pool;
-    io->pool = NULL;    
-    if (0 && pool) {
-        apr_pool_clear(pool);
-        if (m->spare_pool) {
-            apr_pool_destroy(m->spare_pool);
-        }
-        m->spare_pool = pool;
+    if (io->pool) {
+        apr_pool_destroy(io->pool);
     }
 
     check_tx_free(m);
@@ -1006,17 +1003,11 @@ apr_status_t h2_mplx_reprioritize(h2_mplx *m, h2_stream_pri_cmp *cmp, void *ctx)
 
 static h2_io *open_io(h2_mplx *m, int stream_id, const h2_request *request)
 {
-    apr_pool_t *io_pool = m->spare_pool;
+    apr_pool_t *io_pool;
     h2_io *io;
     
-    if (!io_pool) {
-        apr_pool_create(&io_pool, m->pool);
-        apr_pool_tag(io_pool, "h2_io");
-    }
-    else {
-        m->spare_pool = NULL;
-    }
-    
+    apr_pool_create(&io_pool, m->pool);
+    apr_pool_tag(io_pool, "h2_io");
     io = h2_io_create(stream_id, io_pool, m->bucket_alloc, request);
     h2_io_set_add(m->stream_ios, io);
     
@@ -1074,10 +1065,23 @@ static h2_task *pop_task(h2_mplx *m)
             }
         }
         else if (io) {
-            conn_rec *slave = h2_slave_create(m->c, m->pool, m->spare_allocator);
-            m->spare_allocator = NULL;
+            conn_rec *slave, **pslave;
+            int new_conn = 0;
+            
+            pslave = (conn_rec **)apr_array_pop(m->spare_slaves);
+            if (pslave) {
+                slave = *pslave;
+            }
+            else {
+                slave = h2_slave_create(m->c, m->pool, NULL);
+                new_conn = 1;
+            }
+            
             io->task = task = h2_task_create(m->id, io->request, slave, m);
             apr_table_setn(slave->notes, H2_TASK_ID_NOTE, task->id);
+            if (new_conn) {
+                h2_slave_run_pre_connection(slave, ap_get_conn_socket(slave));
+            }
             io->worker_started = 1;
             io->started_at = apr_time_now();
             if (sid > m->max_stream_started) {
index 840f34b464efe90d1df0d5e86068619b80d89153..eef8bf1aba6b593aebf2c015fc9cd69caae445e6 100644 (file)
@@ -96,8 +96,7 @@ struct h2_mplx {
     apr_size_t stream_max_mem;
     apr_interval_time_t stream_timeout;
     
-    apr_pool_t *spare_pool;           /* spare pool, ready for next io */
-    apr_allocator_t *spare_allocator;
+    apr_array_header_t *spare_slaves; /* spare slave connections */
     
     struct h2_workers *workers;
     apr_size_t tx_handles_reserved;
index 3e8667aa23a205dfe06d4dfbcd1a3b4036407c45..32483d9332a3e047592c59c45863dc73f496c652 100644 (file)
@@ -145,7 +145,7 @@ void h2_ngn_shed_abort(h2_ngn_shed *shed)
 
 static void ngn_add_task(h2_req_engine *ngn, h2_task *task)
 {
-    h2_ngn_entry *entry = apr_pcalloc(task->c->pool, sizeof(*entry));
+    h2_ngn_entry *entry = apr_pcalloc(task->pool, sizeof(*entry));
     APR_RING_ELEM_INIT(entry, link);
     entry->task = task;
     H2_REQ_ENTRIES_INSERT_TAIL(&ngn->entries, entry);
@@ -186,7 +186,7 @@ apr_status_t h2_ngn_shed_push_task(h2_ngn_shed *shed, const char *ngn_type,
     /* no existing engine or being shut down, start a new one */
     if (einit) {
         apr_status_t status;
-        apr_pool_t *pool = task->c->pool;
+        apr_pool_t *pool = task->pool;
         h2_req_engine *newngn;
         
         newngn = apr_pcalloc(pool, sizeof(*ngn));
index b722f5281e5850bec902031aa11e8774a222fbf1..b273a05c2b32e5cad8128ab00001dc4f60440381 100644 (file)
@@ -55,7 +55,7 @@ static apr_status_t h2_filter_stream_input(ap_filter_t* filter,
                                            apr_read_type_e block,
                                            apr_off_t readbytes)
 {
-    h2_task *task = filter->ctx;
+    h2_task *task = h2_ctx_cget_task(filter->c);
     AP_DEBUG_ASSERT(task);
     if (!task->input) {
         return APR_ECONNABORTED;
@@ -67,7 +67,7 @@ static apr_status_t h2_filter_stream_input(ap_filter_t* filter,
 static apr_status_t h2_filter_stream_output(ap_filter_t* filter,
                                             apr_bucket_brigade* brigade)
 {
-    h2_task *task = filter->ctx;
+    h2_task *task = h2_ctx_cget_task(filter->c);
     AP_DEBUG_ASSERT(task);
     if (!task->output) {
         return APR_ECONNABORTED;
@@ -75,15 +75,15 @@ static apr_status_t h2_filter_stream_output(ap_filter_t* filter,
     return h2_task_output_write(task->output, filter, brigade);
 }
 
-static apr_status_t h2_filter_read_response(ap_filter_t* f,
+static apr_status_t h2_filter_read_response(ap_filter_t* filter,
                                             apr_bucket_brigade* bb)
 {
-    h2_task *task = f->ctx;
+    h2_task *task = h2_ctx_cget_task(filter->c);
     AP_DEBUG_ASSERT(task);
     if (!task->output || !task->output->from_h1) {
         return APR_ECONNABORTED;
     }
-    return h2_from_h1_read_response(task->output->from_h1, f, bb);
+    return h2_from_h1_read_response(task->output->from_h1, filter, bb);
 }
 
 /*******************************************************************************
@@ -142,15 +142,13 @@ static int h2_task_pre_conn(conn_rec* c, void *arg)
     ctx = h2_ctx_get(c, 0);
     (void)arg;
     if (h2_ctx_is_task(ctx)) {
-        h2_task *task = h2_ctx_get_task(ctx);
-        
         ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
                       "h2_h2, pre_connection, found stream task");
         
         /* Add our own, network level in- and output filters.
          */
-        ap_add_input_filter("H2_TO_H1", task, NULL, c);
-        ap_add_output_filter("H1_TO_H2", task, NULL, c);
+        ap_add_input_filter("H2_TO_H1", NULL, NULL, c);
+        ap_add_output_filter("H1_TO_H2", NULL, NULL, c);
     }
     return OK;
 }
@@ -158,7 +156,11 @@ static int h2_task_pre_conn(conn_rec* c, void *arg)
 h2_task *h2_task_create(long session_id, const h2_request *req, 
                         conn_rec *c, h2_mplx *mplx)
 {
-    h2_task *task     = apr_pcalloc(c->pool, sizeof(h2_task));
+    apr_pool_t *pool;
+    h2_task *task;
+    
+    apr_pool_create(&pool, c->pool);
+    task = apr_pcalloc(pool, sizeof(h2_task));
     if (task == NULL) {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, c,
                       APLOGNO(02941) "h2_task(%ld-%d): create stream task", 
@@ -167,20 +169,27 @@ h2_task *h2_task_create(long session_id, const h2_request *req,
         return NULL;
     }
     
-    task->id          = apr_psprintf(c->pool, "%ld-%d", session_id, req->id);
+    task->id          = apr_psprintf(pool, "%ld-%d", session_id, req->id);
     task->stream_id   = req->id;
     task->c           = c;
     task->mplx        = mplx;
+    task->pool        = pool;
     task->request     = req;
     task->input_eos   = !req->body;
     task->ser_headers = req->serialize;
     task->blocking    = 1;
 
     h2_ctx_create_for(c, task);
-
     return task;
 }
 
+void h2_task_destroy(h2_task *task)
+{
+    if (task->pool) {
+        apr_pool_destroy(task->pool);
+    }
+}
+
 void h2_task_set_io_blocking(h2_task *task, int blocking)
 {
     task->blocking = blocking;
@@ -197,7 +206,7 @@ apr_status_t h2_task_do(h2_task *task, apr_thread_cond_t *cond)
     
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, task->c,
                   "h2_task(%s): process connection", task->id);
-    ap_process_connection(task->c, ap_get_conn_socket(task->c));
+    ap_run_process_connection(task->c);
     
     if (task->frozen) {
         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, task->c,
index fd3e8c9b39cbedae9a005b4c837294f3821db5cf..15a1d3cb2c0ec4ded6d7459dc4336a7b9038ca2a 100644 (file)
@@ -52,7 +52,8 @@ struct h2_task {
     const char *id;
     int stream_id;
     conn_rec *c;
-    struct h2_mplx *mplx;    
+    struct h2_mplx *mplx;
+    apr_pool_t *pool;
     const struct h2_request *request;
     
     unsigned int filters_set : 1;
@@ -74,6 +75,8 @@ struct h2_task {
 h2_task *h2_task_create(long session_id, const struct h2_request *req, 
                         conn_rec *c, struct h2_mplx *mplx);
 
+void h2_task_destroy(h2_task *task);
+
 apr_status_t h2_task_do(h2_task *task, struct apr_thread_cond_t *cond);
 
 void h2_task_register_hooks(void);
index 7409c363db6a83fba923a7cd519349bdba4a0d97..3993b6b40c835aa92765d51380263c314f814211 100644 (file)
@@ -45,9 +45,8 @@ static int ser_header(void *ctx, const char *name, const char *value)
 
 h2_task_input *h2_task_input_create(h2_task *task, conn_rec *c)
 {
-    h2_task_input *input = apr_pcalloc(c->pool, sizeof(h2_task_input));
+    h2_task_input *input = apr_pcalloc(task->pool, sizeof(h2_task_input));
     if (input) {
-        input->c = c;
         input->task = task;
         input->bb = NULL;
         input->block = APR_BLOCK_READ;
@@ -56,7 +55,7 @@ h2_task_input *h2_task_input_create(h2_task *task, conn_rec *c)
             ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
                           "h2_task_input(%s): serialize request %s %s", 
                           task->id, task->request->method, task->request->path);
-            input->bb = apr_brigade_create(c->pool, c->bucket_alloc);
+            input->bb = apr_brigade_create(task->pool, c->bucket_alloc);
             apr_brigade_printf(input->bb, NULL, NULL, "%s %s HTTP/1.1\r\n", 
                                task->request->method, task->request->path);
             apr_table_do(ser_header, input, task->request->headers, NULL);
@@ -66,7 +65,7 @@ h2_task_input *h2_task_input_create(h2_task *task, conn_rec *c)
             }
         }
         else if (!input->task->input_eos) {
-            input->bb = apr_brigade_create(c->pool, c->bucket_alloc);
+            input->bb = apr_brigade_create(task->pool, c->bucket_alloc);
         }
         else {
             /* We do not serialize and have eos already, no need to
index 1488dcab49e90aba1d27274ab242e292e040ed2b..c8913cacf27b0c92b53989ccdc068bb855cedb08 100644 (file)
@@ -26,7 +26,6 @@ struct h2_task;
 
 typedef struct h2_task_input h2_task_input;
 struct h2_task_input {
-    conn_rec *c;
     struct h2_task *task;
     apr_bucket_brigade *bb;
     apr_read_type_e block;
index 1ff08484c9e42b5d1d0a3830a2bac5bbcee3066f..a15a80cf713c23adc761c11875b48aa456b0b539 100644 (file)
 
 h2_task_output *h2_task_output_create(h2_task *task, conn_rec *c)
 {
-    h2_task_output *output = apr_pcalloc(c->pool, sizeof(h2_task_output));
+    h2_task_output *output = apr_pcalloc(task->pool, sizeof(h2_task_output));
     if (output) {
-        output->c = c;
         output->task = task;
-        output->state = H2_TASK_OUT_INIT;
-        output->from_h1 = h2_from_h1_create(task->stream_id, c->pool);
+        output->from_h1 = h2_from_h1_create(task->stream_id, task->pool);
     }
     return output;
 }
@@ -54,7 +52,7 @@ static apr_table_t *get_trailers(h2_task_output *output)
             output->trailers_passed = 1;
             if (h2_task_logio_add_bytes_out) {
                 /* counter trailers as if we'd do a HTTP/1.1 serialization */
-                h2_task_logio_add_bytes_out(output->c, 
+                h2_task_logio_add_bytes_out(output->task->c, 
                                             h2_util_table_bytes(response->trailers, 3)+1);
             }
             return response->trailers;
@@ -72,14 +70,14 @@ static apr_status_t open_response(h2_task_output *output, ap_filter_t *f,
         if (f) {
             /* This happens currently when ap_die(status, r) is invoked
              * by a read request filter. */
-            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, output->c, APLOGNO(03204)
+            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, output->task->c, APLOGNO(03204)
                           "h2_task_output(%s): write without response by %s "
                           "for %s %s %s",
                           output->task->id, caller, 
                           output->task->request->method, 
                           output->task->request->authority, 
                           output->task->request->path);
-            output->c->aborted = 1;
+            output->task->c->aborted = 1;
         }
         if (output->task->io) {
             apr_thread_cond_broadcast(output->task->io);
@@ -90,10 +88,10 @@ static apr_status_t open_response(h2_task_output *output, ap_filter_t *f,
     if (h2_task_logio_add_bytes_out) {
         /* count headers as if we'd do a HTTP/1.1 serialization */
         output->written = h2_util_table_bytes(response->headers, 3)+1;
-        h2_task_logio_add_bytes_out(output->c, output->written);
+        h2_task_logio_add_bytes_out(output->task->c, output->written);
     }
     get_trailers(output);
-    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, output->c, APLOGNO(03348)
+    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, output->task->c, APLOGNO(03348)
                   "h2_task(%s): open response to %s %s %s",
                   output->task->id, output->task->request->method, 
                   output->task->request->authority, 
@@ -109,7 +107,7 @@ static apr_status_t write_brigade_raw(h2_task_output *output,
     apr_status_t status;
 
     apr_brigade_length(bb, 0, &written);
-    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, output->c,
+    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, output->task->c,
                   "h2_task(%s): write response body (%ld bytes)", 
                   output->task->id, (long)written);
     
@@ -125,7 +123,7 @@ static apr_status_t write_brigade_raw(h2_task_output *output,
     if (status == APR_SUCCESS) {
         output->written += written;
         if (h2_task_logio_add_bytes_out) {
-            h2_task_logio_add_bytes_out(output->c, written);
+            h2_task_logio_add_bytes_out(output->task->c, written);
         }
     }
     return status;
@@ -141,20 +139,20 @@ apr_status_t h2_task_output_write(h2_task_output *output,
     apr_status_t status = APR_SUCCESS;
     
     if (APR_BRIGADE_EMPTY(bb)) {
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, output->c,
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, output->task->c,
                       "h2_task(%s): empty write", output->task->id);
         return APR_SUCCESS;
     }
     
     if (output->task->frozen) {
-        h2_util_bb_log(output->c, output->task->stream_id, APLOG_TRACE2,
+        h2_util_bb_log(output->task->c, output->task->stream_id, APLOG_TRACE2,
                        "frozen task output write, ignored", bb);
         return APR_SUCCESS;
     }
     
-    if (output->state == H2_TASK_OUT_INIT) {
+    if (!output->response_open) {
         status = open_response(output, f, bb, "write");
-        output->state = H2_TASK_OUT_STARTED;
+        output->response_open = 1;
     }
     
     /* Attempt to write saved brigade first */
@@ -171,13 +169,13 @@ apr_status_t h2_task_output_write(h2_task_output *output,
     
     /* If the passed brigade is not empty, save it before return */
     if (status == APR_SUCCESS && !APR_BRIGADE_EMPTY(bb)) {
-        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, output->c,
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, output->task->c,
                       "h2_task(%s): could not write all, saving brigade", 
                       output->task->id);
         if (!output->bb) {
-            output->bb = apr_brigade_create(output->c->pool, output->c->bucket_alloc);
+            output->bb = apr_brigade_create(output->task->pool, output->task->c->bucket_alloc);
         }
-        return ap_save_brigade(f, &output->bb, &bb, output->c->pool);
+        return ap_save_brigade(f, &output->bb, &bb, output->task->pool);
     }
     
     return status;
index 76705820725357b15a5cde5b9539dad83dec2289..ba396f07ebd0ccdf75147a7a4fbdc45a49f12cb8 100644 (file)
@@ -26,20 +26,13 @@ struct h2_mplx;
 struct h2_task;
 struct h2_from_h1;
 
-typedef enum {
-    H2_TASK_OUT_INIT,
-    H2_TASK_OUT_STARTED,
-    H2_TASK_OUT_DONE,
-} h2_task_out_state_t;
-
 typedef struct h2_task_output h2_task_output;
 
 struct h2_task_output {
-    conn_rec *c;
     struct h2_task *task;
-    h2_task_out_state_t state;
     struct h2_from_h1 *from_h1;
     
+    unsigned int response_open : 1;
     unsigned int trailers_passed : 1;
 
     apr_off_t written;
index e84a4aa72f3f9473c6c8821528c834ec3df8cd19..94a2987ca03b0256ebcf1df46a2ad0bfe9c1dda6 100644 (file)
@@ -494,9 +494,6 @@ apr_status_t h2_util_move(apr_bucket_brigade *to, apr_bucket_brigade *from,
                     if (APR_BUCKET_IS_EOS(b)) {
                         APR_BRIGADE_INSERT_TAIL(to, apr_bucket_eos_create(to->bucket_alloc));
                     }
-                    else if (APR_BUCKET_IS_FLUSH(b)) {
-                        APR_BRIGADE_INSERT_TAIL(to, apr_bucket_flush_create(to->bucket_alloc));
-                    }
                     else {
                         /* ignore */
                     }
index 70f8c790efabaf9beb4a024906a0cb4feb5dcd10..2cf3d67e9b2e24ce7e131d7c7990adeee71848fb 100644 (file)
@@ -26,7 +26,7 @@
  * @macro
  * Version number of the http2 module as c string
  */
-#define MOD_HTTP2_VERSION "1.4.2"
+#define MOD_HTTP2_VERSION "1.4.3"
 
 /**
  * @macro
@@ -34,7 +34,7 @@
  * release. This is a 24 bit number with 8 bits for major number, 8 bits
  * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
  */
-#define MOD_HTTP2_VERSION_NUM 0x010402
+#define MOD_HTTP2_VERSION_NUM 0x010403
 
 
 #endif /* mod_h2_h2_version_h */