From 69c05dad40bf2f5468dc464b3113e9f7a5c0246d Mon Sep 17 00:00:00 2001
From: CentOS Sources
Date: Nov 13 2018 08:03:33 +0000
Subject: import httpd24-httpd-2.4.34-7.el7
---
diff --git a/.gitignore b/.gitignore
index 657ad18..ff5c489 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/httpd-2.4.27.tar.bz2
+SOURCES/httpd-2.4.34.tar.bz2
diff --git a/.httpd24-httpd.metadata b/.httpd24-httpd.metadata
index d0b8573..939981a 100644
--- a/.httpd24-httpd.metadata
+++ b/.httpd24-httpd.metadata
@@ -1 +1 @@
-699e4e917e8fb5fd7d0ce7e009f8256ed02ec6fc SOURCES/httpd-2.4.27.tar.bz2
+94d6e274273903ed153479c7701fa03761abf93d SOURCES/httpd-2.4.34.tar.bz2
diff --git a/SOURCES/00-proxy.conf b/SOURCES/00-proxy.conf
index 448eb63..f0f84c2 100644
--- a/SOURCES/00-proxy.conf
+++ b/SOURCES/00-proxy.conf
@@ -14,4 +14,5 @@ LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_hcheck_module modules/mod_proxy_hcheck.so
LoadModule proxy_scgi_module modules/mod_proxy_scgi.so
+LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
diff --git a/SOURCES/01-md.conf b/SOURCES/01-md.conf
new file mode 100644
index 0000000..2739202
--- /dev/null
+++ b/SOURCES/01-md.conf
@@ -0,0 +1 @@
+LoadModule md_module modules/mod_md.so
diff --git a/SOURCES/httpd-2.4.12-skiplist.patch b/SOURCES/httpd-2.4.12-skiplist.patch
deleted file mode 100644
index e514785..0000000
--- a/SOURCES/httpd-2.4.12-skiplist.patch
+++ /dev/null
@@ -1,1021 +0,0 @@
-diff --git a/server/mpm/event/config.m4 b/server/mpm/event/config.m4
-index c891c75..351f1ac 100644
---- a/server/mpm/event/config.m4
-+++ b/server/mpm/event/config.m4
-@@ -7,8 +7,6 @@ elif test $have_threaded_sig_graceful != yes; then
- AC_MSG_RESULT(no - SIG_GRACEFUL cannot be used with a threaded MPM)
- elif test $ac_cv_have_threadsafe_pollset != yes; then
- AC_MSG_RESULT(no - APR_POLLSET_THREADSAFE is not supported)
--elif test $apr_has_skiplist != yes; then
-- AC_MSG_RESULT(no - APR skiplist is not available, need APR 1.5.x or later)
- else
- AC_MSG_RESULT(yes)
- APACHE_MPM_SUPPORTED(event, yes, yes)
-diff --git a/server/mpm/event/config3.m4 b/server/mpm/event/config3.m4
-index 8aa1631..fa9b8af 100644
---- a/server/mpm/event/config3.m4
-+++ b/server/mpm/event/config3.m4
-@@ -2,6 +2,6 @@ dnl ## XXX - Need a more thorough check of the proper flags to use
-
- APACHE_SUBST(MOD_MPM_EVENT_LDADD)
-
--APACHE_MPM_MODULE(event, $enable_mpm_event, event.lo fdqueue.lo,[
-+APACHE_MPM_MODULE(event, $enable_mpm_event, event.lo fdqueue.lo apr_skiplist.lo,[
- AC_CHECK_FUNCS(pthread_kill)
- ], , [\$(MOD_MPM_EVENT_LDADD)])
-diff --git a/server/mpm/event/apr_skiplist.c b/server/mpm/event/apr_skiplist.c
-new file mode 100644
-index 0000000..b4696bd
---- /dev/null
-+++ b/server/mpm/event/apr_skiplist.c
-@@ -0,0 +1,721 @@
-+/* Licensed to the Apache Software Foundation (ASF) under one or more
-+ * contributor license agreements. See the NOTICE file distributed with
-+ * this work for additional information regarding copyright ownership.
-+ * The ASF licenses this file to You under the Apache License, Version 2.0
-+ * (the "License"); you may not use this file except in compliance with
-+ * the License. You may obtain a copy of the License at
-+ *
-+ * http://www.apache.org/licenses/LICENSE-2.0
-+ *
-+ * Unless required by applicable law or agreed to in writing, software
-+ * distributed under the License is distributed on an "AS IS" BASIS,
-+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+ * See the License for the specific language governing permissions and
-+ * limitations under the License.
-+ */
-+
-+/*
-+ * Modified to use APR and APR pools.
-+ * TODO: Is malloc() better? Will long running skiplists grow too much?
-+ * Keep the skiplist_alloc() and skiplist_free() until we know
-+ * Yeah, if using pools it means some bogus cycles for checks
-+ * (and an useless function call for skiplist_free) which we
-+ * can removed if/when needed.
-+ */
-+
-+#include "apr_skiplist.h"
-+
-+typedef struct {
-+ apr_skiplistnode **data;
-+ size_t size, pos;
-+ apr_pool_t *p;
-+} apr_skiplist_q;
-+
-+struct apr_skiplist {
-+ apr_skiplist_compare compare;
-+ apr_skiplist_compare comparek;
-+ int height;
-+ int preheight;
-+ size_t size;
-+ apr_skiplistnode *top;
-+ apr_skiplistnode *bottom;
-+ /* These two are needed for appending */
-+ apr_skiplistnode *topend;
-+ apr_skiplistnode *bottomend;
-+ apr_skiplist *index;
-+ apr_array_header_t *memlist;
-+ apr_skiplist_q nodes_q,
-+ stack_q;
-+ apr_pool_t *pool;
-+};
-+
-+struct apr_skiplistnode {
-+ void *data;
-+ apr_skiplistnode *next;
-+ apr_skiplistnode *prev;
-+ apr_skiplistnode *down;
-+ apr_skiplistnode *up;
-+ apr_skiplistnode *previndex;
-+ apr_skiplistnode *nextindex;
-+ apr_skiplist *sl;
-+};
-+
-+static int get_b_rand(void)
-+{
-+ static int ph = 32; /* More bits than we will ever use */
-+ static int randseq;
-+ if (ph > 31) { /* Num bits in return of rand() */
-+ ph = 0;
-+ randseq = rand();
-+ }
-+ return randseq & (1 << ph++);
-+}
-+
-+typedef struct {
-+ size_t size;
-+ apr_array_header_t *list;
-+} memlist_t;
-+
-+typedef struct {
-+ void *ptr;
-+ char inuse;
-+} chunk_t;
-+
-+APR_DECLARE(void *) apr_skiplist_alloc(apr_skiplist *sl, size_t size)
-+{
-+ if (sl->pool) {
-+ void *ptr;
-+ int found_size = 0;
-+ int i;
-+ chunk_t *newchunk;
-+ memlist_t *memlist = (memlist_t *)sl->memlist->elts;
-+ for (i = 0; i < sl->memlist->nelts; i++) {
-+ if (memlist->size == size) {
-+ int j;
-+ chunk_t *chunk = (chunk_t *)memlist->list->elts;
-+ found_size = 1;
-+ for (j = 0; j < memlist->list->nelts; j++) {
-+ if (!chunk->inuse) {
-+ chunk->inuse = 1;
-+ return chunk->ptr;
-+ }
-+ chunk++;
-+ }
-+ break; /* no free of this size; punt */
-+ }
-+ memlist++;
-+ }
-+ /* no free chunks */
-+ ptr = apr_palloc(sl->pool, size);
-+ if (!ptr) {
-+ return ptr;
-+ }
-+ /*
-+ * is this a new sized chunk? If so, we need to create a new
-+ * array of them. Otherwise, re-use what we already have.
-+ */
-+ if (!found_size) {
-+ memlist = apr_array_push(sl->memlist);
-+ memlist->size = size;
-+ memlist->list = apr_array_make(sl->pool, 20, sizeof(chunk_t));
-+ }
-+ newchunk = apr_array_push(memlist->list);
-+ newchunk->ptr = ptr;
-+ newchunk->inuse = 1;
-+ return ptr;
-+ }
-+ else {
-+ return malloc(size);
-+ }
-+}
-+
-+APR_DECLARE(void) apr_skiplist_free(apr_skiplist *sl, void *mem)
-+{
-+ if (!sl->pool) {
-+ free(mem);
-+ }
-+ else {
-+ int i;
-+ memlist_t *memlist = (memlist_t *)sl->memlist->elts;
-+ for (i = 0; i < sl->memlist->nelts; i++) {
-+ int j;
-+ chunk_t *chunk = (chunk_t *)memlist->list->elts;
-+ for (j = 0; j < memlist->list->nelts; j++) {
-+ if (chunk->ptr == mem) {
-+ chunk->inuse = 0;
-+ return;
-+ }
-+ chunk++;
-+ }
-+ memlist++;
-+ }
-+ }
-+}
-+
-+static apr_status_t skiplist_qpush(apr_skiplist_q *q, apr_skiplistnode *m)
-+{
-+ if (q->pos >= q->size) {
-+ apr_skiplistnode **data;
-+ size_t size = (q->pos) ? q->pos * 2 : 32;
-+ if (q->p) {
-+ data = apr_palloc(q->p, size * sizeof(*data));
-+ if (data) {
-+ memcpy(data, q->data, q->pos * sizeof(*data));
-+ }
-+ }
-+ else {
-+ data = realloc(q->data, size * sizeof(*data));
-+ }
-+ if (!data) {
-+ return APR_ENOMEM;
-+ }
-+ q->data = data;
-+ q->size = size;
-+ }
-+ q->data[q->pos++] = m;
-+ return APR_SUCCESS;
-+}
-+
-+static APR_INLINE apr_skiplistnode *skiplist_qpop(apr_skiplist_q *q)
-+{
-+ return (q->pos > 0) ? q->data[--q->pos] : NULL;
-+}
-+
-+static APR_INLINE void skiplist_qclear(apr_skiplist_q *q)
-+{
-+ q->pos = 0;
-+}
-+
-+static apr_skiplistnode *skiplist_new_node(apr_skiplist *sl)
-+{
-+ apr_skiplistnode *m = skiplist_qpop(&sl->nodes_q);
-+ if (!m) {
-+ if (sl->pool) {
-+ m = apr_palloc(sl->pool, sizeof *m);
-+ }
-+ else {
-+ m = malloc(sizeof *m);
-+ }
-+ }
-+ return m;
-+}
-+
-+static apr_status_t skiplist_free_node(apr_skiplist *sl, apr_skiplistnode *m)
-+{
-+ return skiplist_qpush(&sl->nodes_q, m);
-+}
-+
-+static apr_status_t skiplisti_init(apr_skiplist **s, apr_pool_t *p)
-+{
-+ apr_skiplist *sl;
-+ if (p) {
-+ sl = apr_pcalloc(p, sizeof(apr_skiplist));
-+ sl->memlist = apr_array_make(p, 20, sizeof(memlist_t));
-+ sl->pool = sl->nodes_q.p = sl->stack_q.p = p;
-+ }
-+ else {
-+ sl = calloc(1, sizeof(apr_skiplist));
-+ if (!sl) {
-+ return APR_ENOMEM;
-+ }
-+ }
-+ *s = sl;
-+ return APR_SUCCESS;
-+}
-+
-+static int indexing_comp(void *a, void *b)
-+{
-+ void *ac = (void *) (((apr_skiplist *) a)->compare);
-+ void *bc = (void *) (((apr_skiplist *) b)->compare);
-+ return ((ac < bc) ? -1 : ((ac > bc) ? 1 : 0));
-+}
-+
-+static int indexing_compk(void *ac, void *b)
-+{
-+ void *bc = (void *) (((apr_skiplist *) b)->compare);
-+ return ((ac < bc) ? -1 : ((ac > bc) ? 1 : 0));
-+}
-+
-+APR_DECLARE(apr_status_t) apr_skiplist_init(apr_skiplist **s, apr_pool_t *p)
-+{
-+ apr_skiplist *sl;
-+ skiplisti_init(s, p);
-+ sl = *s;
-+ skiplisti_init(&(sl->index), p);
-+ apr_skiplist_set_compare(sl->index, indexing_comp, indexing_compk);
-+ return APR_SUCCESS;
-+}
-+
-+APR_DECLARE(void) apr_skiplist_set_compare(apr_skiplist *sl,
-+ apr_skiplist_compare comp,
-+ apr_skiplist_compare compk)
-+{
-+ if (sl->compare && sl->comparek) {
-+ apr_skiplist_add_index(sl, comp, compk);
-+ }
-+ else {
-+ sl->compare = comp;
-+ sl->comparek = compk;
-+ }
-+}
-+
-+APR_DECLARE(void) apr_skiplist_add_index(apr_skiplist *sl,
-+ apr_skiplist_compare comp,
-+ apr_skiplist_compare compk)
-+{
-+ apr_skiplistnode *m;
-+ apr_skiplist *ni;
-+ int icount = 0;
-+ apr_skiplist_find(sl->index, (void *)comp, &m);
-+ if (m) {
-+ return; /* Index already there! */
-+ }
-+ skiplisti_init(&ni, sl->pool);
-+ apr_skiplist_set_compare(ni, comp, compk);
-+ /* Build the new index... This can be expensive! */
-+ m = apr_skiplist_insert(sl->index, ni);
-+ while (m->prev) {
-+ m = m->prev;
-+ icount++;
-+ }
-+ for (m = apr_skiplist_getlist(sl); m; apr_skiplist_next(sl, &m)) {
-+ int j = icount - 1;
-+ apr_skiplistnode *nsln;
-+ nsln = apr_skiplist_insert(ni, m->data);
-+ /* skip from main index down list */
-+ while (j > 0) {
-+ m = m->nextindex;
-+ j--;
-+ }
-+ /* insert this node in the indexlist after m */
-+ nsln->nextindex = m->nextindex;
-+ if (m->nextindex) {
-+ m->nextindex->previndex = nsln;
-+ }
-+ nsln->previndex = m;
-+ m->nextindex = nsln;
-+ }
-+}
-+
-+static int skiplisti_find_compare(apr_skiplist *sl, void *data,
-+ apr_skiplistnode **ret,
-+ apr_skiplist_compare comp)
-+{
-+ int count = 0;
-+ apr_skiplistnode *m;
-+ m = sl->top;
-+ while (m) {
-+ if (m->next) {
-+ int compared = comp(data, m->next->data);
-+ if (compared == 0) {
-+ m = m->next;
-+ while (m->down) {
-+ m = m->down;
-+ }
-+ *ret = m;
-+ return count;
-+ }
-+ if (compared > 0) {
-+ m = m->next;
-+ count++;
-+ continue;
-+ }
-+ }
-+ m = m->down;
-+ count++;
-+ }
-+ *ret = NULL;
-+ return count;
-+}
-+
-+APR_DECLARE(void *) apr_skiplist_find_compare(apr_skiplist *sli, void *data,
-+ apr_skiplistnode **iter,
-+ apr_skiplist_compare comp)
-+{
-+ apr_skiplistnode *m;
-+ apr_skiplist *sl;
-+ if (!comp) {
-+ if (iter) {
-+ *iter = NULL;
-+ }
-+ return NULL;
-+ }
-+ if (comp == sli->compare || !sli->index) {
-+ sl = sli;
-+ }
-+ else {
-+ apr_skiplist_find(sli->index, (void *)comp, &m);
-+ if (!m) {
-+ if (iter) {
-+ *iter = NULL;
-+ }
-+ return NULL;
-+ }
-+ sl = (apr_skiplist *) m->data;
-+ }
-+ skiplisti_find_compare(sl, data, &m, sl->comparek);
-+ if (iter) {
-+ *iter = m;
-+ }
-+ return (m) ? m->data : NULL;
-+}
-+
-+APR_DECLARE(void *) apr_skiplist_find(apr_skiplist *sl, void *data, apr_skiplistnode **iter)
-+{
-+ return apr_skiplist_find_compare(sl, data, iter, sl->compare);
-+}
-+
-+
-+APR_DECLARE(apr_skiplistnode *) apr_skiplist_getlist(apr_skiplist *sl)
-+{
-+ if (!sl->bottom) {
-+ return NULL;
-+ }
-+ return sl->bottom->next;
-+}
-+
-+APR_DECLARE(void *) apr_skiplist_next(apr_skiplist *sl, apr_skiplistnode **iter)
-+{
-+ if (!*iter) {
-+ return NULL;
-+ }
-+ *iter = (*iter)->next;
-+ return (*iter) ? ((*iter)->data) : NULL;
-+}
-+
-+APR_DECLARE(void *) apr_skiplist_previous(apr_skiplist *sl, apr_skiplistnode **iter)
-+{
-+ if (!*iter) {
-+ return NULL;
-+ }
-+ *iter = (*iter)->prev;
-+ return (*iter) ? ((*iter)->data) : NULL;
-+}
-+
-+static APR_INLINE int skiplist_height(const apr_skiplist *sl)
-+{
-+ /* Skiplists (even empty) always have a top node, although this
-+ * implementation defers its creation until the first insert, or
-+ * deletes it with the last remove. We want the real height here.
-+ */
-+ return sl->height ? sl->height : 1;
-+}
-+
-+APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert_compare(apr_skiplist *sl, void *data,
-+ apr_skiplist_compare comp)
-+{
-+ apr_skiplistnode *m, *p, *tmp, *ret = NULL;
-+ int ch, nh = 1;
-+
-+ if (!comp) {
-+ return NULL;
-+ }
-+
-+ ch = skiplist_height(sl);
-+ if (sl->preheight) {
-+ while (nh < sl->preheight && get_b_rand()) {
-+ nh++;
-+ }
-+ }
-+ else {
-+ while (nh <= ch && get_b_rand()) {
-+ nh++;
-+ }
-+ }
-+
-+ /* Now we have in nh the height at which we wish to insert our new node,
-+ * and in ch the current height: don't create skip paths to the inserted
-+ * element until the walk down through the tree (which decrements ch)
-+ * reaches nh. From there, any walk down pushes the current node on a
-+ * stack (the node(s) after which we would insert) to pop back through
-+ * for insertion later.
-+ */
-+ m = sl->top;
-+ while (m) {
-+ if (m->next) {
-+ int compared = comp(data, m->next->data);
-+ if (compared == 0) {
-+ /* Keep the existing element(s) */
-+ skiplist_qclear(&sl->stack_q);
-+ return NULL;
-+ }
-+ if (compared > 0) {
-+ m = m->next;
-+ continue;
-+ }
-+ }
-+ if (ch <= nh) {
-+ /* push on stack */
-+ skiplist_qpush(&sl->stack_q, m);
-+ }
-+ m = m->down;
-+ ch--;
-+ }
-+ /* Pop the stack and insert nodes */
-+ p = NULL;
-+ while ((m = skiplist_qpop(&sl->stack_q))) {
-+ tmp = skiplist_new_node(sl);
-+ tmp->next = m->next;
-+ if (m->next) {
-+ m->next->prev = tmp;
-+ }
-+ m->next = tmp;
-+ tmp->prev = m;
-+ tmp->up = NULL;
-+ tmp->nextindex = tmp->previndex = NULL;
-+ tmp->down = p;
-+ if (p) {
-+ p->up = tmp;
-+ }
-+ else {
-+ /* This sets ret to the bottom-most node we are inserting */
-+ ret = tmp;
-+ }
-+ tmp->data = data;
-+ tmp->sl = sl;
-+ p = tmp;
-+ }
-+
-+ /* Now we are sure the node is inserted, grow our tree to 'nh' tall */
-+ for (; sl->height < nh; sl->height++) {
-+ m = skiplist_new_node(sl);
-+ tmp = skiplist_new_node(sl);
-+ m->up = m->prev = m->nextindex = m->previndex = NULL;
-+ m->next = tmp;
-+ m->down = sl->top;
-+ m->data = NULL;
-+ m->sl = sl;
-+ if (sl->top) {
-+ sl->top->up = m;
-+ }
-+ else {
-+ sl->bottom = sl->bottomend = m;
-+ }
-+ sl->top = sl->topend = tmp->prev = m;
-+ tmp->up = tmp->next = tmp->nextindex = tmp->previndex = NULL;
-+ tmp->down = p;
-+ tmp->data = data;
-+ tmp->sl = sl;
-+ if (p) {
-+ p->up = tmp;
-+ }
-+ else {
-+ /* This sets ret to the bottom-most node we are inserting */
-+ ret = tmp;
-+ }
-+ p = tmp;
-+ }
-+ if (sl->index != NULL) {
-+ /*
-+ * this is a external insertion, we must insert into each index as
-+ * well
-+ */
-+ apr_skiplistnode *ni, *li;
-+ li = ret;
-+ for (p = apr_skiplist_getlist(sl->index); p; apr_skiplist_next(sl->index, &p)) {
-+ apr_skiplist *sli = (apr_skiplist *)p->data;
-+ ni = apr_skiplist_insert_compare(sli, ret->data, sli->compare);
-+ li->nextindex = ni;
-+ ni->previndex = li;
-+ li = ni;
-+ }
-+ }
-+ sl->size++;
-+ return ret;
-+}
-+
-+APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert(apr_skiplist *sl, void *data)
-+{
-+ return apr_skiplist_insert_compare(sl, data, sl->compare);
-+}
-+
-+#if 0
-+void skiplist_print_struct(apr_skiplist * sl, char *prefix)
-+{
-+ apr_skiplistnode *p, *q;
-+ fprintf(stderr, "Skiplist Structure (height: %d)\n", sl->height);
-+ p = sl->bottom;
-+ while (p) {
-+ q = p;
-+ fprintf(stderr, prefix);
-+ while (q) {
-+ fprintf(stderr, "%p ", q->data);
-+ q = q->up;
-+ }
-+ fprintf(stderr, "\n");
-+ p = p->next;
-+ }
-+}
-+#endif
-+
-+static int skiplisti_remove(apr_skiplist *sl, apr_skiplistnode *m, apr_skiplist_freefunc myfree)
-+{
-+ apr_skiplistnode *p;
-+ if (!m) {
-+ return 0;
-+ }
-+ if (m->nextindex) {
-+ skiplisti_remove(m->nextindex->sl, m->nextindex, NULL);
-+ }
-+ while (m->up) {
-+ m = m->up;
-+ }
-+ while (m) {
-+ p = m;
-+ p->prev->next = p->next;/* take me out of the list */
-+ if (p->next) {
-+ p->next->prev = p->prev; /* take me out of the list */
-+ }
-+ m = m->down;
-+ /* This only frees the actual data in the bottom one */
-+ if (!m && myfree && p->data) {
-+ myfree(p->data);
-+ }
-+ skiplist_free_node(sl, p);
-+ }
-+ sl->size--;
-+ while (sl->top && sl->top->next == NULL) {
-+ /* While the row is empty and we are not on the bottom row */
-+ p = sl->top;
-+ sl->top = sl->top->down;/* Move top down one */
-+ if (sl->top) {
-+ sl->top->up = NULL; /* Make it think its the top */
-+ }
-+ skiplist_free_node(sl, p);
-+ sl->height--;
-+ }
-+ if (!sl->top) {
-+ sl->bottom = sl->bottomend = NULL;
-+ sl->topend = NULL;
-+ }
-+ return skiplist_height(sl);
-+}
-+
-+APR_DECLARE(int) apr_skiplist_remove_compare(apr_skiplist *sli,
-+ void *data,
-+ apr_skiplist_freefunc myfree, apr_skiplist_compare comp)
-+{
-+ apr_skiplistnode *m;
-+ apr_skiplist *sl;
-+ if (!comp) {
-+ return 0;
-+ }
-+ if (comp == sli->comparek || !sli->index) {
-+ sl = sli;
-+ }
-+ else {
-+ apr_skiplist_find(sli->index, (void *)comp, &m);
-+ if (!m) {
-+ return 0;
-+ }
-+ sl = (apr_skiplist *) m->data;
-+ }
-+ skiplisti_find_compare(sl, data, &m, comp);
-+ if (!m) {
-+ return 0;
-+ }
-+ while (m->previndex) {
-+ m = m->previndex;
-+ }
-+ return skiplisti_remove(sl, m, myfree);
-+}
-+
-+APR_DECLARE(int) apr_skiplist_remove(apr_skiplist *sl, void *data, apr_skiplist_freefunc myfree)
-+{
-+ return apr_skiplist_remove_compare(sl, data, myfree, sl->comparek);
-+}
-+
-+APR_DECLARE(void) apr_skiplist_remove_all(apr_skiplist *sl, apr_skiplist_freefunc myfree)
-+{
-+ /*
-+ * This must remove even the place holder nodes (bottom though top)
-+ * because we specify in the API that one can free the Skiplist after
-+ * making this call without memory leaks
-+ */
-+ apr_skiplistnode *m, *p, *u;
-+ m = sl->bottom;
-+ while (m) {
-+ p = m->next;
-+ if (myfree && p && p->data) {
-+ myfree(p->data);
-+ }
-+ do {
-+ u = m->up;
-+ skiplist_free_node(sl, m);
-+ m = u;
-+ } while (m);
-+ m = p;
-+ }
-+ sl->top = sl->bottom = NULL;
-+ sl->topend = sl->bottomend = NULL;
-+ sl->height = 0;
-+ sl->size = 0;
-+}
-+
-+APR_DECLARE(void *) apr_skiplist_pop(apr_skiplist *a, apr_skiplist_freefunc myfree)
-+{
-+ apr_skiplistnode *sln;
-+ void *data = NULL;
-+ sln = apr_skiplist_getlist(a);
-+ if (sln) {
-+ data = sln->data;
-+ skiplisti_remove(a, sln, myfree);
-+ }
-+ return data;
-+}
-+
-+APR_DECLARE(void *) apr_skiplist_peek(apr_skiplist *a)
-+{
-+ apr_skiplistnode *sln;
-+ sln = apr_skiplist_getlist(a);
-+ if (sln) {
-+ return sln->data;
-+ }
-+ return NULL;
-+}
-+
-+static void skiplisti_destroy(void *vsl)
-+{
-+ apr_skiplist_destroy(vsl, NULL);
-+}
-+
-+APR_DECLARE(void) apr_skiplist_destroy(apr_skiplist *sl, apr_skiplist_freefunc myfree)
-+{
-+ while (apr_skiplist_pop(sl->index, skiplisti_destroy) != NULL)
-+ ;
-+ apr_skiplist_remove_all(sl, myfree);
-+ if (!sl->pool) {
-+ while (sl->nodes_q.pos)
-+ free(sl->nodes_q.data[--sl->nodes_q.pos]);
-+ free(sl->nodes_q.data);
-+ free(sl->stack_q.data);
-+ free(sl);
-+ }
-+}
-+
-+APR_DECLARE(apr_skiplist *) apr_skiplist_merge(apr_skiplist *sl1, apr_skiplist *sl2)
-+{
-+ /* Check integrity! */
-+ apr_skiplist temp;
-+ struct apr_skiplistnode *b2;
-+ if (sl1->bottomend == NULL || sl1->bottomend->prev == NULL) {
-+ apr_skiplist_remove_all(sl1, NULL);
-+ temp = *sl1;
-+ *sl1 = *sl2;
-+ *sl2 = temp;
-+ /* swap them so that sl2 can be freed normally upon return. */
-+ return sl1;
-+ }
-+ if(sl2->bottom == NULL || sl2->bottom->next == NULL) {
-+ apr_skiplist_remove_all(sl2, NULL);
-+ return sl1;
-+ }
-+ /* This is what makes it brute force... Just insert :/ */
-+ b2 = apr_skiplist_getlist(sl2);
-+ while (b2) {
-+ apr_skiplist_insert(sl1, b2->data);
-+ apr_skiplist_next(sl2, &b2);
-+ }
-+ apr_skiplist_remove_all(sl2, NULL);
-+ return sl1;
-+}
-diff --git a/server/mpm/event/apr_skiplist.h b/server/mpm/event/apr_skiplist.h
-new file mode 100644
-index 0000000..f56ff22
---- /dev/null
-+++ b/server/mpm/event/apr_skiplist.h
-@@ -0,0 +1,263 @@
-+/* Licensed to the Apache Software Foundation (ASF) under one or more
-+ * contributor license agreements. See the NOTICE file distributed with
-+ * this work for additional information regarding copyright ownership.
-+ * The ASF licenses this file to You under the Apache License, Version 2.0
-+ * (the "License"); you may not use this file except in compliance with
-+ * the License. You may obtain a copy of the License at
-+ *
-+ * http://www.apache.org/licenses/LICENSE-2.0
-+ *
-+ * Unless required by applicable law or agreed to in writing, software
-+ * distributed under the License is distributed on an "AS IS" BASIS,
-+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+ * See the License for the specific language governing permissions and
-+ * limitations under the License.
-+ */
-+
-+#ifndef APR_SKIPLIST_H
-+#define APR_SKIPLIST_H
-+/**
-+ * @file apr_skiplist.h
-+ * @brief APR skip list implementation
-+ */
-+
-+#include "apr.h"
-+#include "apr_portable.h"
-+#include
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif /* __cplusplus */
-+
-+/**
-+ * @defgroup apr_skiplist Skip list implementation
-+ * Refer to http://en.wikipedia.org/wiki/Skip_list for information
-+ * about the purpose of and ideas behind skip lists.
-+ * @ingroup APR
-+ * @{
-+ */
-+
-+/**
-+ * apr_skiplist_compare is the function type that must be implemented
-+ * per object type that is used in a skip list for comparisons to maintain
-+ * order. A value <0 indicates placement after this node; a value of 0
-+ * indicates collision with this exact node; a value >0 indicates placement
-+ * before this node.
-+ * */
-+typedef int (*apr_skiplist_compare) (void *, void *);
-+
-+/**
-+ * apr_skiplist_freefunc is the function type that must be implemented
-+ * to handle elements as they are removed from a skip list.
-+ */
-+typedef void (*apr_skiplist_freefunc) (void *);
-+
-+/** Opaque structure used to represent the skip list */
-+struct apr_skiplist;
-+/** Opaque structure used to represent the skip list */
-+typedef struct apr_skiplist apr_skiplist;
-+
-+/**
-+ * Opaque structure used to represent abstract nodes in the skip list
-+ * (an abstraction above the raw elements which are collected in the
-+ * skip list).
-+ */
-+struct apr_skiplistnode;
-+/** Opaque structure */
-+typedef struct apr_skiplistnode apr_skiplistnode;
-+
-+/**
-+ * Allocate memory using the same mechanism as the skip list.
-+ * @param sl The skip list
-+ * @param size The amount to allocate
-+ * @remark If a pool was provided to apr_skiplist_init(), memory will
-+ * be allocated from the pool or from a free list maintained with
-+ * the skip list. Otherwise, memory will be allocated using the
-+ * C standard library heap functions.
-+ */
-+APR_DECLARE(void *) apr_skiplist_alloc(apr_skiplist *sl, size_t size);
-+
-+/**
-+ * Free memory using the same mechanism as the skip list.
-+ * @param sl The skip list
-+ * @param mem The object to free
-+ * @remark If a pool was provided to apr_skiplist_init(), memory will
-+ * be added to a free list maintained with the skip list and be available
-+ * to operations on the skip list or to other calls to apr_skiplist_alloc().
-+ * Otherwise, memory will be freed using the C standard library heap
-+ * functions.
-+ */
-+APR_DECLARE(void) apr_skiplist_free(apr_skiplist *sl, void *mem);
-+
-+/**
-+ * Allocate a new skip list
-+ * @param sl The pointer in which to return the newly created skip list
-+ * @param p The pool from which to allocate the skip list (optional).
-+ * @remark Unlike most APR functions, a pool is optional. If no pool
-+ * is provided, the C standard library heap functions will be used instead.
-+ */
-+APR_DECLARE(apr_status_t) apr_skiplist_init(apr_skiplist **sl, apr_pool_t *p);
-+
-+/**
-+ * Set the comparison functions to be used for searching the skip list.
-+ * @param sl The skip list
-+ * @param XXX1 FIXME
-+ * @param XXX2 FIXME
-+ *
-+ * @remark If existing comparison functions are being replaced, the index
-+ * will be replaced during this call. That is a potentially expensive
-+ * operation.
-+ */
-+APR_DECLARE(void) apr_skiplist_set_compare(apr_skiplist *sl, apr_skiplist_compare XXX1,
-+ apr_skiplist_compare XXX2);
-+
-+/**
-+ * Set the indexing functions to the specified comparison functions and
-+ * rebuild the index.
-+ * @param sl The skip list
-+ * @param XXX1 FIXME
-+ * @param XXX2 FIXME
-+ *
-+ * @remark If an index already exists, it will not be replaced and the
-+ * comparison functions will not be changed.
-+ */
-+APR_DECLARE(void) apr_skiplist_add_index(apr_skiplist *sl, apr_skiplist_compare XXX1,
-+ apr_skiplist_compare XXX2);
-+
-+/**
-+ * Return the list maintained by the skip list abstraction.
-+ * @param sl The skip list
-+ */
-+APR_DECLARE(apr_skiplistnode *) apr_skiplist_getlist(apr_skiplist *sl);
-+
-+/**
-+ * Return the next matching element in the skip list using the specified
-+ * comparison function.
-+ * @param sl The skip list
-+ * @param data The value to search for
-+ * @param iter A pointer to the returned skip list node representing the element
-+ * found
-+ * @param func The comparison function to use
-+ */
-+APR_DECLARE(void *) apr_skiplist_find_compare(apr_skiplist *sl,
-+ void *data,
-+ apr_skiplistnode **iter,
-+ apr_skiplist_compare func);
-+
-+/**
-+ * Return the next matching element in the skip list using the current comparison
-+ * function.
-+ * @param sl The skip list
-+ * @param data The value to search for
-+ * @param iter A pointer to the returned skip list node representing the element
-+ * found
-+ */
-+APR_DECLARE(void *) apr_skiplist_find(apr_skiplist *sl, void *data, apr_skiplistnode **iter);
-+
-+/**
-+ * Return the next element in the skip list.
-+ * @param sl The skip list
-+ * @param iter On entry, a pointer to the skip list node to start with; on return,
-+ * a pointer to the skip list node representing the element returned
-+ * @remark If iter points to a NULL value on entry, NULL will be returned.
-+ */
-+APR_DECLARE(void *) apr_skiplist_next(apr_skiplist *sl, apr_skiplistnode **iter);
-+
-+/**
-+ * Return the previous element in the skip list.
-+ * @param sl The skip list
-+ * @param iter On entry, a pointer to the skip list node to start with; on return,
-+ * a pointer to the skip list node representing the element returned
-+ * @remark If iter points to a NULL value on entry, NULL will be returned.
-+ */
-+APR_DECLARE(void *) apr_skiplist_previous(apr_skiplist *sl, apr_skiplistnode **iter);
-+
-+/**
-+ * Insert an element into the skip list using the specified comparison function
-+ * if it does not already exist.
-+ * @param sl The skip list
-+ * @param data The element to insert
-+ * @param comp The comparison function to use for placement into the skip list
-+ */
-+APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert_compare(apr_skiplist *sl,
-+ void *data, apr_skiplist_compare comp);
-+
-+/**
-+ * Insert an element into the skip list using the existing comparison function
-+ * if it does not already exist (as determined by the comparison function)
-+ * @param sl The skip list
-+ * @param data The element to insert
-+ * @remark If no comparison function has been set for the skip list, the element
-+ * will not be inserted and NULL will be returned.
-+ */
-+APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert(apr_skiplist* sl, void *data);
-+
-+/**
-+ * Remove an element from the skip list using the specified comparison function for
-+ * locating the element. In the case of duplicates, the 1st entry will be removed.
-+ * @param sl The skip list
-+ * @param data The element to remove
-+ * @param myfree A function to be called for each removed element
-+ * @param comp The comparison function to use for placement into the skip list
-+ * @remark If the element is not found, 0 will be returned. Otherwise, the heightXXX
-+ * will be returned.
-+ */
-+APR_DECLARE(int) apr_skiplist_remove_compare(apr_skiplist *sl, void *data,
-+ apr_skiplist_freefunc myfree, apr_skiplist_compare comp);
-+
-+/**
-+ * Remove an element from the skip list using the existing comparison function for
-+ * locating the element. In the case of duplicates, the 1st entry will be removed.
-+ * @param sl The skip list
-+ * @param data The element to remove
-+ * @param myfree A function to be called for each removed element
-+ * @remark If the element is not found, 0 will be returned. Otherwise, the heightXXX
-+ * will be returned.
-+ * @remark If no comparison function has been set for the skip list, the element
-+ * will not be removed and 0 will be returned.
-+ */
-+APR_DECLARE(int) apr_skiplist_remove(apr_skiplist *sl, void *data, apr_skiplist_freefunc myfree);
-+
-+/**
-+ * Remove all elements from the skip list.
-+ * @param sl The skip list
-+ * @param myfree A function to be called for each removed element
-+ */
-+APR_DECLARE(void) apr_skiplist_remove_all(apr_skiplist *sl, apr_skiplist_freefunc myfree);
-+
-+/**
-+ * Remove each element from the skip list.
-+ * @param sl The skip list
-+ * @param myfree A function to be called for each removed element
-+ */
-+APR_DECLARE(void) apr_skiplist_destroy(apr_skiplist *sl, apr_skiplist_freefunc myfree);
-+
-+/**
-+ * Return the first element in the skip list, removing the element from the skip list.
-+ * @param sl The skip list
-+ * @param myfree A function to be called for the removed element
-+ * @remark NULL will be returned if there are no elements
-+ */
-+APR_DECLARE(void *) apr_skiplist_pop(apr_skiplist *sl, apr_skiplist_freefunc myfree);
-+
-+/**
-+ * Return the first element in the skip list, leaving the element in the skip list.
-+ * @param sl The skip list
-+ * @remark NULL will be returned if there are no elements
-+ */
-+APR_DECLARE(void *) apr_skiplist_peek(apr_skiplist *sl);
-+
-+/**
-+ * Merge two skip lists. XXX SEMANTICS
-+ * @param sl1 One of two skip lists to be merged
-+ * @param sl2 The other of two skip lists to be merged
-+ */
-+APR_DECLARE(apr_skiplist *) apr_skiplist_merge(apr_skiplist *sl1, apr_skiplist *sl2);
-+
-+/** @} */
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* ! APR_SKIPLIST_H */
diff --git a/SOURCES/httpd-2.4.26-sslalpnthunks.patch b/SOURCES/httpd-2.4.26-sslalpnthunks.patch
deleted file mode 100644
index d662ec7..0000000
--- a/SOURCES/httpd-2.4.26-sslalpnthunks.patch
+++ /dev/null
@@ -1,118 +0,0 @@
-
-Support building against OpenSSL 1.0.1 but using ALPN support from
-OpenSSL 1.0.2 if possible, using the dynamic loader to look up
-symbols at run-time.
-
---- httpd-2.4.26/modules/ssl/config.m4.sslalpnthunks
-+++ httpd-2.4.26/modules/ssl/config.m4
-@@ -49,6 +49,15 @@
- fi
- ])
-
-+AC_ARG_ENABLE(tls-alpn-thunks,
-+APACHE_HELP_STRING(--enable-tls-alpn-thunks,Enable support for ALPN thunks in mod_ssl),[
-+ if test "$enableval" = "yes"; then
-+ AC_DEFINE(HAVE_TLS_ALPN_THUNKS, 1, [Define if support for ALPN thunks is enabled])
-+ AC_MSG_NOTICE([Enabled support for ALPN thunks in mod_ssl])
-+ fi
-+])
-+
-+
- # Ensure that other modules can pick up mod_ssl.h
- APR_ADDTO(INCLUDES, [-I\$(top_srcdir)/$modpath_current])
-
-diff -uap httpd-2.4.26/modules/ssl/mod_ssl.c.sslalpnthunks httpd-2.4.26/modules/ssl/mod_ssl.c
---- httpd-2.4.26/modules/ssl/mod_ssl.c.sslalpnthunks
-+++ httpd-2.4.26/modules/ssl/mod_ssl.c
-@@ -725,6 +725,9 @@
- &ssl_authz_provider_verify_client,
- AP_AUTH_INTERNAL_PER_CONF);
-
-+#ifdef HAVE_TLS_ALPN_THUNKS
-+ modssl_init_alpn_thunks();
-+#endif
- }
-
- module AP_MODULE_DECLARE_DATA ssl_module = {
-diff -uap httpd-2.4.26/modules/ssl/ssl_engine_init.c.sslalpnthunks httpd-2.4.26/modules/ssl/ssl_engine_init.c
---- httpd-2.4.26/modules/ssl/ssl_engine_init.c.sslalpnthunks
-+++ httpd-2.4.26/modules/ssl/ssl_engine_init.c
-@@ -47,6 +47,50 @@
- #define KEYTYPES "RSA or DSA"
- #endif
-
-+#ifdef HAVE_TLS_ALPN_THUNKS
-+#include
-+
-+/* During initialization, fetch pointers to OpenSSL functions if
-+ * available from the dynamic loader, and store these for later
-+ * use. */
-+typedef int (ssl_alpn_callback_fn)(SSL *ssl, const unsigned char **out,
-+ unsigned char *outlen, const unsigned char *in,
-+ unsigned int inlen, void *arg);
-+static void SSL_CTX_set_alpn_select_cb(SSL_CTX *, ssl_alpn_callback_fn *, void *);
-+int modssl_SSL_set_alpn_protos(SSL *, unsigned char *, unsigned);
-+
-+static typeof(SSL_CTX_set_alpn_select_cb) *thunk_set_alpn_select_cb;
-+static typeof(modssl_SSL_set_alpn_protos) *thunk_set_alpn_protos;
-+
-+void modssl_init_alpn_thunks(void)
-+{
-+ thunk_set_alpn_select_cb = dlsym(RTLD_NEXT, "SSL_CTX_set_alpn_select_cb");
-+ thunk_set_alpn_protos = dlsym(RTLD_NEXT, "SSL_set_alpn_protos");
-+
-+ if (!thunk_set_alpn_select_cb || !thunk_set_alpn_protos) {
-+ /* All or nothing... */
-+ thunk_set_alpn_select_cb = NULL;
-+ thunk_set_alpn_protos = NULL;
-+ }
-+}
-+
-+static void SSL_CTX_set_alpn_select_cb(SSL_CTX *ssl, ssl_alpn_callback_fn *cb, void *ud)
-+{
-+ if (thunk_set_alpn_select_cb)
-+ thunk_set_alpn_select_cb(ssl, cb, ud);
-+}
-+
-+int modssl_SSL_set_alpn_protos(SSL *ssl, unsigned char *ps, unsigned plen)
-+{
-+ if (thunk_set_alpn_protos)
-+ return thunk_set_alpn_protos(ssl, ps, plen);
-+ else
-+ /* Succeed silently; less harmless than failing and logging
-+ * warnings. */
-+ return 0;
-+}
-+#endif /* HAVE_TLS_ALPN_THUNKS */
-+
- #if OPENSSL_VERSION_NUMBER < 0x10100000L
- /* OpenSSL Pre-1.1.0 compatibility */
- /* Taken from OpenSSL 1.1.0 snapshot 20160410 */
-diff -uap httpd-2.4.26/modules/ssl/ssl_private.h.sslalpnthunks httpd-2.4.26/modules/ssl/ssl_private.h
---- httpd-2.4.26/modules/ssl/ssl_private.h.sslalpnthunks
-+++ httpd-2.4.26/modules/ssl/ssl_private.h
-@@ -199,6 +199,24 @@
- #include
- #endif
-
-+#ifdef HAVE_TLS_ALPN_THUNKS
-+
-+#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
-+#error Cannot enable TLS ALPN thunks if OpenSSL support is present
-+#endif
-+
-+#define TLSEXT_TYPE_application_layer_protocol_negotiation 16
-+
-+#define SSL_set_alpn_protos(s, p, l) modssl_SSL_set_alpn_protos(s, p, l)
-+
-+/* Thunk for SSL_set_alpn_protos(). */
-+int modssl_SSL_set_alpn_protos(SSL *, unsigned char *, unsigned);
-+
-+/* Initialize thunks. */
-+void modssl_init_alpn_thunks(void);
-+
-+#endif
-+
- /* ALPN Protocol Negotiation */
- #if defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
- #define HAVE_TLS_ALPN
diff --git a/SOURCES/httpd-2.4.27-CVE-2017-9798.patch b/SOURCES/httpd-2.4.27-CVE-2017-9798.patch
deleted file mode 100644
index 90bf4f7..0000000
--- a/SOURCES/httpd-2.4.27-CVE-2017-9798.patch
+++ /dev/null
@@ -1,15 +0,0 @@
---- a/server/core.c 2017/09/08 13:10:16 1807753
-+++ b/server/core.c 2017/09/08 13:13:11 1807754
-@@ -2266,6 +2266,12 @@
- /* method has not been registered yet, but resource restriction
- * is always checked before method handling, so register it.
- */
-+ if (cmd->pool == cmd->temp_pool) {
-+ /* In .htaccess, we can't globally register new methods. */
-+ return apr_psprintf(cmd->pool, "Could not register method '%s' "
-+ "for %s from .htaccess configuration",
-+ method, cmd->cmd->name);
-+ }
- methnum = ap_method_register(cmd->pool,
- apr_pstrdup(cmd->pool, method));
- }
diff --git a/SOURCES/httpd-2.4.27-mod_authz_dbd-missing-query.patch b/SOURCES/httpd-2.4.27-mod_authz_dbd-missing-query.patch
deleted file mode 100644
index 2d66043..0000000
--- a/SOURCES/httpd-2.4.27-mod_authz_dbd-missing-query.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-diff --git a/modules/aaa/mod_authz_dbd.c b/modules/aaa/mod_authz_dbd.c
-index 52aab38..2c468e0 100644
---- a/modules/aaa/mod_authz_dbd.c
-+++ b/modules/aaa/mod_authz_dbd.c
-@@ -119,7 +119,7 @@ static int authz_dbd_login(request_rec *r, authz_dbd_cfg *cfg,
- const char *newuri = NULL;
- int nrows;
- const char *message;
-- ap_dbd_t *dbd = dbd_handle(r);
-+ ap_dbd_t *dbd = NULL;
- apr_dbd_prepared_t *query;
- apr_dbd_results_t *res = NULL;
- apr_dbd_row_t *row = NULL;
-@@ -129,6 +129,7 @@ static int authz_dbd_login(request_rec *r, authz_dbd_cfg *cfg,
- "No query configured for %s!", action);
- return HTTP_INTERNAL_SERVER_ERROR;
- }
-+ dbd = dbd_handle(r);
- if (dbd == NULL) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02902)
- "No db handle available for %s! "
-@@ -213,7 +213,7 @@ static int authz_dbd_group_query(request_rec *r, authz_dbd_cfg *cfg,
- /* SELECT group FROM authz WHERE user = %s */
- int rv;
- const char *message;
-- ap_dbd_t *dbd = dbd_handle(r);
-+ ap_dbd_t *dbd = NULL;
- apr_dbd_prepared_t *query;
- apr_dbd_results_t *res = NULL;
- apr_dbd_row_t *row = NULL;
-@@ -223,6 +223,7 @@ static int authz_dbd_group_query(request_rec *r, authz_dbd_cfg *cfg,
- "No query configured for dbd-group!");
- return HTTP_INTERNAL_SERVER_ERROR;
- }
-+ dbd = dbd_handle(r);
- if (dbd == NULL) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02903)
- "No db handle available for dbd-query! "
diff --git a/SOURCES/httpd-2.4.27-r1807771.patch b/SOURCES/httpd-2.4.27-r1807771.patch
deleted file mode 100644
index eeb3905..0000000
--- a/SOURCES/httpd-2.4.27-r1807771.patch
+++ /dev/null
@@ -1,760 +0,0 @@
-diff --git a/modules/http2/h2_bucket_beam.c b/modules/http2/h2_bucket_beam.c
-index fff3f5d..9f3bc70 100644
---- a/modules/http2/h2_bucket_beam.c
-+++ b/modules/http2/h2_bucket_beam.c
-@@ -287,7 +287,7 @@ static apr_size_t calc_buffered(h2_bucket_beam *beam)
- /* do not count */
- }
- else if (APR_BUCKET_IS_FILE(b)) {
-- /* if unread, has no real mem footprint. how to test? */
-+ /* if unread, has no real mem footprint. */
- }
- else {
- len += b->length;
-@@ -316,32 +316,80 @@ static apr_size_t calc_space_left(h2_bucket_beam *beam)
- return APR_SIZE_MAX;
- }
-
--static apr_status_t wait_cond(h2_bucket_beam *beam, apr_thread_mutex_t *lock)
-+static int buffer_is_empty(h2_bucket_beam *beam)
- {
-- if (beam->timeout > 0) {
-- return apr_thread_cond_timedwait(beam->cond, lock, beam->timeout);
-+ return ((!beam->recv_buffer || APR_BRIGADE_EMPTY(beam->recv_buffer))
-+ && H2_BLIST_EMPTY(&beam->send_list));
-+}
-+
-+static apr_status_t wait_empty(h2_bucket_beam *beam, apr_read_type_e block,
-+ apr_thread_mutex_t *lock)
-+{
-+ apr_status_t rv = APR_SUCCESS;
-+
-+ while (!buffer_is_empty(beam) && APR_SUCCESS == rv) {
-+ if (APR_BLOCK_READ != block || !lock) {
-+ rv = APR_EAGAIN;
-+ }
-+ else if (beam->timeout > 0) {
-+ rv = apr_thread_cond_timedwait(beam->change, lock, beam->timeout);
-+ }
-+ else {
-+ rv = apr_thread_cond_wait(beam->change, lock);
-+ }
- }
-- else {
-- return apr_thread_cond_wait(beam->cond, lock);
-+ return rv;
-+}
-+
-+static apr_status_t wait_not_empty(h2_bucket_beam *beam, apr_read_type_e block,
-+ apr_thread_mutex_t *lock)
-+{
-+ apr_status_t rv = APR_SUCCESS;
-+
-+ while (buffer_is_empty(beam) && APR_SUCCESS == rv) {
-+ if (beam->aborted) {
-+ rv = APR_ECONNABORTED;
-+ }
-+ else if (beam->closed) {
-+ rv = APR_EOF;
-+ }
-+ else if (APR_BLOCK_READ != block || !lock) {
-+ rv = APR_EAGAIN;
-+ }
-+ else if (beam->timeout > 0) {
-+ rv = apr_thread_cond_timedwait(beam->change, lock, beam->timeout);
-+ }
-+ else {
-+ rv = apr_thread_cond_wait(beam->change, lock);
-+ }
- }
-+ return rv;
- }
-
--static apr_status_t r_wait_space(h2_bucket_beam *beam, apr_read_type_e block,
-- h2_beam_lock *pbl, apr_size_t *premain)
-+static apr_status_t wait_not_full(h2_bucket_beam *beam, apr_read_type_e block,
-+ apr_size_t *pspace_left, h2_beam_lock *bl)
- {
-- *premain = calc_space_left(beam);
-- while (!beam->aborted && *premain <= 0
-- && (block == APR_BLOCK_READ) && pbl->mutex) {
-- apr_status_t status;
-- report_prod_io(beam, 1, pbl);
-- status = wait_cond(beam, pbl->mutex);
-- if (APR_STATUS_IS_TIMEUP(status)) {
-- return status;
-+ apr_status_t rv = APR_SUCCESS;
-+ apr_size_t left;
-+
-+ while (0 == (left = calc_space_left(beam)) && APR_SUCCESS == rv) {
-+ if (beam->aborted) {
-+ rv = APR_ECONNABORTED;
-+ }
-+ else if (block != APR_BLOCK_READ || !bl->mutex) {
-+ rv = APR_EAGAIN;
-+ }
-+ else {
-+ if (beam->timeout > 0) {
-+ rv = apr_thread_cond_timedwait(beam->change, bl->mutex, beam->timeout);
-+ }
-+ else {
-+ rv = apr_thread_cond_wait(beam->change, bl->mutex);
-+ }
- }
-- r_purge_sent(beam);
-- *premain = calc_space_left(beam);
- }
-- return beam->aborted? APR_ECONNABORTED : APR_SUCCESS;
-+ *pspace_left = left;
-+ return rv;
- }
-
- static void h2_beam_emitted(h2_bucket_beam *beam, h2_beam_proxy *proxy)
-@@ -404,8 +452,8 @@ static void h2_beam_emitted(h2_bucket_beam *beam, h2_beam_proxy *proxy)
- if (!bl.mutex) {
- r_purge_sent(beam);
- }
-- else if (beam->cond) {
-- apr_thread_cond_broadcast(beam->cond);
-+ else {
-+ apr_thread_cond_broadcast(beam->change);
- }
- leave_yellow(beam, &bl);
- }
-@@ -425,9 +473,7 @@ static apr_status_t beam_close(h2_bucket_beam *beam)
- {
- if (!beam->closed) {
- beam->closed = 1;
-- if (beam->cond) {
-- apr_thread_cond_broadcast(beam->cond);
-- }
-+ apr_thread_cond_broadcast(beam->change);
- }
- return APR_SUCCESS;
- }
-@@ -582,7 +628,7 @@ apr_status_t h2_beam_create(h2_bucket_beam **pbeam, apr_pool_t *pool,
- apr_interval_time_t timeout)
- {
- h2_bucket_beam *beam;
-- apr_status_t status = APR_SUCCESS;
-+ apr_status_t rv = APR_SUCCESS;
-
- beam = apr_pcalloc(pool, sizeof(*beam));
- if (!beam) {
-@@ -601,16 +647,15 @@ apr_status_t h2_beam_create(h2_bucket_beam **pbeam, apr_pool_t *pool,
- beam->max_buf_size = max_buf_size;
- beam->timeout = timeout;
-
-- status = apr_thread_mutex_create(&beam->lock, APR_THREAD_MUTEX_DEFAULT,
-- pool);
-- if (status == APR_SUCCESS) {
-- status = apr_thread_cond_create(&beam->cond, pool);
-- if (status == APR_SUCCESS) {
-+ rv = apr_thread_mutex_create(&beam->lock, APR_THREAD_MUTEX_DEFAULT, pool);
-+ if (APR_SUCCESS == rv) {
-+ rv = apr_thread_cond_create(&beam->change, pool);
-+ if (APR_SUCCESS == rv) {
- apr_pool_pre_cleanup_register(pool, beam, beam_cleanup);
- *pbeam = beam;
- }
- }
-- return status;
-+ return rv;
- }
-
- void h2_beam_buffer_size_set(h2_bucket_beam *beam, apr_size_t buffer_size)
-@@ -691,9 +736,7 @@ void h2_beam_abort(h2_bucket_beam *beam)
- h2_blist_cleanup(&beam->send_list);
- report_consumption(beam, &bl);
- }
-- if (beam->cond) {
-- apr_thread_cond_broadcast(beam->cond);
-- }
-+ apr_thread_cond_broadcast(beam->change);
- leave_yellow(beam, &bl);
- }
- }
-@@ -730,18 +773,7 @@ apr_status_t h2_beam_wait_empty(h2_bucket_beam *beam, apr_read_type_e block)
- h2_beam_lock bl;
-
- if ((status = enter_yellow(beam, &bl)) == APR_SUCCESS) {
-- while (status == APR_SUCCESS
-- && !H2_BLIST_EMPTY(&beam->send_list)
-- && !H2_BPROXY_LIST_EMPTY(&beam->proxies)) {
-- if (block == APR_NONBLOCK_READ || !bl.mutex) {
-- status = APR_EAGAIN;
-- break;
-- }
-- if (beam->cond) {
-- apr_thread_cond_broadcast(beam->cond);
-- }
-- status = wait_cond(beam, bl.mutex);
-- }
-+ status = wait_empty(beam, block, bl.mutex);
- leave_yellow(beam, &bl);
- }
- return status;
-@@ -761,12 +793,17 @@ static void move_to_hold(h2_bucket_beam *beam,
- static apr_status_t append_bucket(h2_bucket_beam *beam,
- apr_bucket *b,
- apr_read_type_e block,
-+ apr_size_t *pspace_left,
- h2_beam_lock *pbl)
- {
- const char *data;
- apr_size_t len;
-- apr_size_t space_left = 0;
- apr_status_t status;
-+ int can_beam, check_len;
-+
-+ if (beam->aborted) {
-+ return APR_ECONNABORTED;
-+ }
-
- if (APR_BUCKET_IS_METADATA(b)) {
- if (APR_BUCKET_IS_EOS(b)) {
-@@ -777,30 +814,46 @@ static apr_status_t append_bucket(h2_bucket_beam *beam,
- return APR_SUCCESS;
- }
- else if (APR_BUCKET_IS_FILE(b)) {
-- /* file bucket lengths do not really count */
-+ /* For file buckets the problem is their internal readpool that
-+ * is used on the first read to allocate buffer/mmap.
-+ * Since setting aside a file bucket will de-register the
-+ * file cleanup function from the previous pool, we need to
-+ * call that only from the sender thread.
-+ *
-+ * Currently, we do not handle file bucket with refcount > 1 as
-+ * the beam is then not in complete control of the file's lifetime.
-+ * Which results in the bug that a file get closed by the receiver
-+ * while the sender or the beam still have buckets using it.
-+ *
-+ * Additionally, we allow callbacks to prevent beaming file
-+ * handles across. The use case for this is to limit the number
-+ * of open file handles and rather use a less efficient beam
-+ * transport. */
-+ apr_bucket_file *bf = b->data;
-+ apr_file_t *fd = bf->fd;
-+ can_beam = (bf->refcount.refcount == 1);
-+ if (can_beam && beam->can_beam_fn) {
-+ can_beam = beam->can_beam_fn(beam->can_beam_ctx, beam, fd);
-+ }
-+ check_len = !can_beam;
- }
- else {
-- space_left = calc_space_left(beam);
-- if (space_left > 0 && b->length == ((apr_size_t)-1)) {
-+ if (b->length == ((apr_size_t)-1)) {
- const char *data;
- status = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
- if (status != APR_SUCCESS) {
- return status;
- }
- }
--
-- if (space_left <= 0) {
-- status = r_wait_space(beam, block, pbl, &space_left);
-- if (status != APR_SUCCESS) {
-- return status;
-- }
-- if (space_left <= 0) {
-- return APR_EAGAIN;
-- }
-- }
-- /* space available, maybe need bucket split */
-+ check_len = 1;
- }
-
-+ if (check_len) {
-+ if (b->length > *pspace_left) {
-+ apr_bucket_split(b, *pspace_left);
-+ }
-+ *pspace_left -= b->length;
-+ }
-
- /* The fundamental problem is that reading a sender bucket from
- * a receiver thread is a total NO GO, because the bucket might use
-@@ -830,32 +883,8 @@ static apr_status_t append_bucket(h2_bucket_beam *beam,
- apr_bucket_heap_make(b, data, len, NULL);
- }
- }
-- else if (APR_BUCKET_IS_FILE(b)) {
-- /* For file buckets the problem is their internal readpool that
-- * is used on the first read to allocate buffer/mmap.
-- * Since setting aside a file bucket will de-register the
-- * file cleanup function from the previous pool, we need to
-- * call that only from the sender thread.
-- *
-- * Currently, we do not handle file bucket with refcount > 1 as
-- * the beam is then not in complete control of the file's lifetime.
-- * Which results in the bug that a file get closed by the receiver
-- * while the sender or the beam still have buckets using it.
-- *
-- * Additionally, we allow callbacks to prevent beaming file
-- * handles across. The use case for this is to limit the number
-- * of open file handles and rather use a less efficient beam
-- * transport. */
-- apr_bucket_file *bf = b->data;
-- apr_file_t *fd = bf->fd;
-- int can_beam = (bf->refcount.refcount == 1);
-- if (can_beam && beam->can_beam_fn) {
-- can_beam = beam->can_beam_fn(beam->can_beam_ctx, beam, fd);
-- }
-- if (can_beam) {
-- status = apr_bucket_setaside(b, beam->send_pool);
-- }
-- /* else: enter ENOTIMPL case below */
-+ else if (APR_BUCKET_IS_FILE(b) && can_beam) {
-+ status = apr_bucket_setaside(b, beam->send_pool);
- }
-
- if (status == APR_ENOTIMPL) {
-@@ -865,12 +894,6 @@ static apr_status_t append_bucket(h2_bucket_beam *beam,
- * a counter example).
- * We do the read while in the sender thread, so that the bucket may
- * use pools/allocators safely. */
-- if (space_left < APR_BUCKET_BUFF_SIZE) {
-- space_left = APR_BUCKET_BUFF_SIZE;
-- }
-- if (space_left < b->length) {
-- apr_bucket_split(b, space_left);
-- }
- status = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
- if (status == APR_SUCCESS) {
- status = apr_bucket_setaside(b, beam->send_pool);
-@@ -884,7 +907,7 @@ static apr_status_t append_bucket(h2_bucket_beam *beam,
- APR_BUCKET_REMOVE(b);
- H2_BLIST_INSERT_TAIL(&beam->send_list, b);
- beam->sent_bytes += b->length;
--
-+
- return APR_SUCCESS;
- }
-
-@@ -904,7 +927,8 @@ apr_status_t h2_beam_send(h2_bucket_beam *beam,
- apr_read_type_e block)
- {
- apr_bucket *b;
-- apr_status_t status = APR_SUCCESS;
-+ apr_status_t rv = APR_SUCCESS;
-+ apr_size_t space_left = 0;
- h2_beam_lock bl;
-
- /* Called from the sender thread to add buckets to the beam */
-@@ -914,23 +938,31 @@ apr_status_t h2_beam_send(h2_bucket_beam *beam,
-
- if (beam->aborted) {
- move_to_hold(beam, sender_bb);
-- status = APR_ECONNABORTED;
-+ rv = APR_ECONNABORTED;
- }
- else if (sender_bb) {
-- int force_report = !APR_BRIGADE_EMPTY(sender_bb);
-- while (!APR_BRIGADE_EMPTY(sender_bb) && status == APR_SUCCESS) {
-+ int force_report = !APR_BRIGADE_EMPTY(sender_bb);
-+
-+ space_left = calc_space_left(beam);
-+ while (!APR_BRIGADE_EMPTY(sender_bb) && APR_SUCCESS == rv) {
-+ if (space_left <= 0) {
-+ report_prod_io(beam, force_report, &bl);
-+ rv = wait_not_full(beam, block, &space_left, &bl);
-+ if (APR_SUCCESS != rv) {
-+ break;
-+ }
-+ }
- b = APR_BRIGADE_FIRST(sender_bb);
-- status = append_bucket(beam, b, block, &bl);
-+ rv = append_bucket(beam, b, block, &space_left, &bl);
- }
-+
- report_prod_io(beam, force_report, &bl);
-- if (beam->cond) {
-- apr_thread_cond_broadcast(beam->cond);
-- }
-+ apr_thread_cond_broadcast(beam->change);
- }
- report_consumption(beam, &bl);
- leave_yellow(beam, &bl);
- }
-- return status;
-+ return rv;
- }
-
- apr_status_t h2_beam_receive(h2_bucket_beam *beam,
-@@ -942,11 +974,16 @@ apr_status_t h2_beam_receive(h2_bucket_beam *beam,
- apr_bucket *bsender, *brecv, *ng;
- int transferred = 0;
- apr_status_t status = APR_SUCCESS;
-- apr_off_t remain = readbytes;
-+ apr_off_t remain;
- int transferred_buckets = 0;
-
- /* Called from the receiver thread to take buckets from the beam */
- if (enter_yellow(beam, &bl) == APR_SUCCESS) {
-+ if (readbytes <= 0) {
-+ readbytes = APR_SIZE_MAX;
-+ }
-+ remain = readbytes;
-+
- transfer:
- if (beam->aborted) {
- recv_buffer_cleanup(beam, &bl);
-@@ -955,11 +992,12 @@ transfer:
- }
-
- /* transfer enough buckets from our receiver brigade, if we have one */
-- while (beam->recv_buffer
-- && !APR_BRIGADE_EMPTY(beam->recv_buffer)
-- && (readbytes <= 0 || remain >= 0)) {
-+ while (remain >= 0
-+ && beam->recv_buffer
-+ && !APR_BRIGADE_EMPTY(beam->recv_buffer)) {
-+
- brecv = APR_BRIGADE_FIRST(beam->recv_buffer);
-- if (readbytes > 0 && brecv->length > 0 && remain <= 0) {
-+ if (brecv->length > 0 && remain <= 0) {
- break;
- }
- APR_BUCKET_REMOVE(brecv);
-@@ -970,11 +1008,11 @@ transfer:
-
- /* transfer from our sender brigade, transforming sender buckets to
- * receiver ones until we have enough */
-- while (!H2_BLIST_EMPTY(&beam->send_list) && (readbytes <= 0 || remain >= 0)) {
-- bsender = H2_BLIST_FIRST(&beam->send_list);
-+ while (remain >= 0 && !H2_BLIST_EMPTY(&beam->send_list)) {
-+
- brecv = NULL;
--
-- if (readbytes > 0 && bsender->length > 0 && remain <= 0) {
-+ bsender = H2_BLIST_FIRST(&beam->send_list);
-+ if (bsender->length > 0 && remain <= 0) {
- break;
- }
-
-@@ -1020,11 +1058,12 @@ transfer:
- * been handed out. See also PR 59348 */
- apr_bucket_file_enable_mmap(ng, 0);
- #endif
-- remain -= bsender->length;
-- ++transferred;
- APR_BUCKET_REMOVE(bsender);
- H2_BLIST_INSERT_TAIL(&beam->hold_list, bsender);
-+
-+ remain -= bsender->length;
- ++transferred;
-+ ++transferred_buckets;
- continue;
- }
- else {
-@@ -1041,6 +1080,7 @@ transfer:
- * receiver bucket references it any more. */
- APR_BUCKET_REMOVE(bsender);
- H2_BLIST_INSERT_TAIL(&beam->hold_list, bsender);
-+
- beam->received_bytes += bsender->length;
- ++transferred_buckets;
-
-@@ -1063,8 +1103,8 @@ transfer:
- }
- }
-
-- if (readbytes > 0 && remain < 0) {
-- /* too much, put some back */
-+ if (remain < 0) {
-+ /* too much, put some back into out recv_buffer */
- remain = readbytes;
- for (brecv = APR_BRIGADE_FIRST(bb);
- brecv != APR_BRIGADE_SENTINEL(bb);
-@@ -1081,15 +1121,7 @@ transfer:
- }
- }
-
-- if (transferred_buckets > 0) {
-- if (beam->cons_ev_cb) {
-- beam->cons_ev_cb(beam->cons_ctx, beam);
-- }
-- }
--
-- if (beam->closed
-- && (!beam->recv_buffer || APR_BRIGADE_EMPTY(beam->recv_buffer))
-- && H2_BLIST_EMPTY(&beam->send_list)) {
-+ if (beam->closed && buffer_is_empty(beam)) {
- /* beam is closed and we have nothing more to receive */
- if (!beam->close_sent) {
- apr_bucket *b = apr_bucket_eos_create(bb->bucket_alloc);
-@@ -1100,28 +1132,23 @@ transfer:
- }
- }
-
-- if (transferred) {
-- if (beam->cond) {
-- apr_thread_cond_broadcast(beam->cond);
-+ if (transferred_buckets > 0) {
-+ if (beam->cons_ev_cb) {
-+ beam->cons_ev_cb(beam->cons_ctx, beam);
- }
-- status = APR_SUCCESS;
- }
-- else if (beam->closed) {
-- status = APR_EOF;
-+
-+ if (transferred) {
-+ apr_thread_cond_broadcast(beam->change);
-+ status = APR_SUCCESS;
- }
-- else if (block == APR_BLOCK_READ && bl.mutex && beam->cond) {
-- status = wait_cond(beam, bl.mutex);
-+ else {
-+ status = wait_not_empty(beam, block, bl.mutex);
- if (status != APR_SUCCESS) {
- goto leave;
- }
- goto transfer;
- }
-- else {
-- if (beam->cond) {
-- apr_thread_cond_broadcast(beam->cond);
-- }
-- status = APR_EAGAIN;
-- }
- leave:
- leave_yellow(beam, &bl);
- }
-diff --git a/modules/http2/h2_bucket_beam.h b/modules/http2/h2_bucket_beam.h
-index 64117ff..7a67455 100644
---- a/modules/http2/h2_bucket_beam.h
-+++ b/modules/http2/h2_bucket_beam.h
-@@ -190,7 +190,7 @@ struct h2_bucket_beam {
- unsigned int tx_mem_limits : 1; /* only memory size counts on transfers */
-
- struct apr_thread_mutex_t *lock;
-- struct apr_thread_cond_t *cond;
-+ struct apr_thread_cond_t *change;
- void *m_ctx;
- h2_beam_mutex_enter *m_enter;
-
-diff --git a/modules/http2/h2_stream.c b/modules/http2/h2_stream.c
-index 925f3d6..1e87b1c 100644
---- a/modules/http2/h2_stream.c
-+++ b/modules/http2/h2_stream.c
-@@ -774,20 +774,20 @@ static apr_bucket *get_first_headers_bucket(apr_bucket_brigade *bb)
- return NULL;
- }
-
--static apr_status_t add_data(h2_stream *stream, apr_off_t requested,
-- apr_off_t *plen, int *peos, int *complete,
-- h2_headers **pheaders)
-+static apr_status_t add_buffered_data(h2_stream *stream, apr_off_t requested,
-+ apr_off_t *plen, int *peos, int *is_all,
-+ h2_headers **pheaders)
- {
- apr_bucket *b, *e;
-
- *peos = 0;
- *plen = 0;
-- *complete = 0;
-+ *is_all = 0;
- if (pheaders) {
- *pheaders = NULL;
- }
-
-- H2_STREAM_OUT_LOG(APLOG_TRACE2, stream, "add_data");
-+ H2_STREAM_OUT_LOG(APLOG_TRACE2, stream, "add_buffered_data");
- b = APR_BRIGADE_FIRST(stream->out_buffer);
- while (b != APR_BRIGADE_SENTINEL(stream->out_buffer)) {
- e = APR_BUCKET_NEXT(b);
-@@ -833,7 +833,7 @@ static apr_status_t add_data(h2_stream *stream, apr_off_t requested,
- }
- b = e;
- }
-- *complete = 1;
-+ *is_all = 1;
- return APR_SUCCESS;
- }
-
-@@ -865,7 +865,7 @@ apr_status_t h2_stream_out_prepare(h2_stream *stream, apr_off_t *plen,
- requested = (*plen > 0)? H2MIN(*plen, max_chunk) : max_chunk;
-
- /* count the buffered data until eos or a headers bucket */
-- status = add_data(stream, requested, plen, peos, &complete, pheaders);
-+ status = add_buffered_data(stream, requested, plen, peos, &complete, pheaders);
-
- if (status == APR_EAGAIN) {
- /* TODO: ugly, someone needs to retrieve the response first */
-@@ -882,28 +882,38 @@ apr_status_t h2_stream_out_prepare(h2_stream *stream, apr_off_t *plen,
- return APR_SUCCESS;
- }
-
-+ /* If there we do not have enough buffered data to satisfy the requested
-+ * length *and* we counted the _complete_ buffer (and did not stop in the middle
-+ * because of meta data there), lets see if we can read more from the
-+ * output beam */
- missing = H2MIN(requested, stream->max_mem) - *plen;
- if (complete && !*peos && missing > 0) {
-+ apr_status_t rv = APR_EOF;
-+
- if (stream->output) {
- H2_STREAM_OUT_LOG(APLOG_TRACE2, stream, "pre");
-- status = h2_beam_receive(stream->output, stream->out_buffer,
-- APR_NONBLOCK_READ,
-- stream->max_mem - *plen);
-+ rv = h2_beam_receive(stream->output, stream->out_buffer,
-+ APR_NONBLOCK_READ, stream->max_mem - *plen);
- H2_STREAM_OUT_LOG(APLOG_TRACE2, stream, "post");
- }
-- else {
-- status = APR_EOF;
-- }
-
-- if (APR_STATUS_IS_EOF(status)) {
-+ if (rv == APR_SUCCESS) {
-+ /* count the buffer again, now that we have read output */
-+ status = add_buffered_data(stream, requested, plen, peos, &complete, pheaders);
-+ }
-+ else if (APR_STATUS_IS_EOF(rv)) {
- apr_bucket *eos = apr_bucket_eos_create(c->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(stream->out_buffer, eos);
- *peos = 1;
-- status = APR_SUCCESS;
- }
-- else if (status == APR_SUCCESS) {
-- /* do it again, now that we have gotten more */
-- status = add_data(stream, requested, plen, peos, &complete, pheaders);
-+ else if (APR_STATUS_IS_EAGAIN(rv)) {
-+ /* we set this is the status of this call only if there
-+ * is no buffered data, see check below */
-+ }
-+ else {
-+ /* real error reading. Give this back directly, even though
-+ * we may have something buffered. */
-+ status = rv;
- }
- }
-
-diff --git a/modules/http2/h2_task.c b/modules/http2/h2_task.c
-index 1ef0d9a..2ab4145 100644
---- a/modules/http2/h2_task.c
-+++ b/modules/http2/h2_task.c
-@@ -129,7 +129,7 @@ static apr_status_t slave_out(h2_task *task, ap_filter_t* f,
- apr_bucket_brigade* bb)
- {
- apr_bucket *b;
-- apr_status_t status = APR_SUCCESS;
-+ apr_status_t rv = APR_SUCCESS;
- int flush = 0, blocking;
-
- if (task->frozen) {
-@@ -148,17 +148,16 @@ static apr_status_t slave_out(h2_task *task, ap_filter_t* f,
- 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);
-- if (!task->output.opened) {
-- for (b = APR_BRIGADE_FIRST(bb);
-- b != APR_BRIGADE_SENTINEL(bb);
-- b = APR_BUCKET_NEXT(b)) {
-- if (APR_BUCKET_IS_FLUSH(b)) {
-- flush = 1;
-- break;
-- }
-+ for (b = APR_BRIGADE_FIRST(bb);
-+ b != APR_BRIGADE_SENTINEL(bb);
-+ b = APR_BUCKET_NEXT(b)) {
-+ if (APR_BUCKET_IS_FLUSH(b) || APR_BUCKET_IS_EOS(b) || AP_BUCKET_IS_EOR(b)) {
-+ flush = 1;
-+ break;
- }
- }
-
-@@ -166,32 +165,48 @@ static apr_status_t slave_out(h2_task *task, ap_filter_t* f,
- /* still have data buffered from previous attempt.
- * setaside and append new data and try to pass the complete data */
- if (!APR_BRIGADE_EMPTY(bb)) {
-- status = ap_save_brigade(f, &task->output.bb, &bb, task->pool);
-+ if (APR_SUCCESS != (rv = ap_save_brigade(f, &task->output.bb, &bb, task->pool))) {
-+ goto out;
-+ }
- }
-- if (status == APR_SUCCESS) {
-- status = send_out(task, task->output.bb, blocking);
-- }
-+ rv = send_out(task, task->output.bb, blocking);
- }
- else {
-- /* no data buffered here, try to pass the brigade directly */
-- status = send_out(task, bb, blocking);
-- if (status == APR_SUCCESS && !APR_BRIGADE_EMPTY(bb)) {
-- /* could not write all, buffer the rest */
-- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, task->c, APLOGNO(03405)
-- "h2_slave_out(%s): saving brigade",
-- task->id);
-- status = ap_save_brigade(f, &task->output.bb, &bb, task->pool);
-- flush = 1;
-+ /* no data buffered previously, pass brigade directly */
-+ rv = send_out(task, bb, blocking);
-+
-+ if (APR_SUCCESS == rv && !APR_BRIGADE_EMPTY(bb)) {
-+ /* output refused to buffer it all, time to open? */
-+ if (!task->output.opened && APR_SUCCESS == (rv = open_output(task))) {
-+ /* Make another attempt to send the data. With the output open,
-+ * the call might be blocking and send all data, so we do not need
-+ * to save the brigade */
-+ goto send;
-+ }
-+ else if (blocking && flush) {
-+ /* Need to keep on doing this. */
-+ goto send;
-+ }
-+
-+ if (APR_SUCCESS == rv) {
-+ /* could not write all, buffer the rest */
-+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, task->c, APLOGNO(03405)
-+ "h2_slave_out(%s): saving brigade", task->id);
-+ ap_assert(NULL);
-+ rv = ap_save_brigade(f, &task->output.bb, &bb, task->pool);
-+ flush = 1;
-+ }
- }
- }
-
-- if (status == APR_SUCCESS && !task->output.opened && flush) {
-+ if (APR_SUCCESS == rv && !task->output.opened && flush) {
- /* got a flush or could not write all, time to tell someone to read */
-- status = open_output(task);
-+ rv = open_output(task);
- }
-- ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, task->c,
-+out:
-+ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, task->c,
- "h2_slave_out(%s): slave_out leave", task->id);
-- return status;
-+ return rv;
- }
-
- static apr_status_t output_finish(h2_task *task)
-diff --git a/modules/http2/h2_version.h b/modules/http2/h2_version.h
-index ca0a13a..c5e356e 100644
---- a/modules/http2/h2_version.h
-+++ b/modules/http2/h2_version.h
-@@ -26,7 +26,7 @@
- * @macro
- * Version number of the http2 module as c string
- */
--#define MOD_HTTP2_VERSION "1.10.7"
-+#define MOD_HTTP2_VERSION "1.10.10"
-
- /**
- * @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 0x010a06
-+#define MOD_HTTP2_VERSION_NUM 0x010a0a
-
-
- #endif /* mod_h2_h2_version_h */
diff --git a/SOURCES/httpd-2.4.3-layout.patch b/SOURCES/httpd-2.4.3-layout.patch
index 5b51353..d60cf6c 100644
--- a/SOURCES/httpd-2.4.3-layout.patch
+++ b/SOURCES/httpd-2.4.3-layout.patch
@@ -31,3 +31,40 @@ Add layout for Fedora.
+ logfiledir: /var/log/httpd24
+ proxycachedir: ${localstatedir}/cache/httpd/proxy
+
+diff --git a/config.layout b/config.layout
+index b471568..6860f3f 100644
+--- a/config.layout
++++ b/config.layout
+@@ -128,31 +128,7 @@
+ runtimedir: ${localstatedir}/run
+ logfiledir: ${localstatedir}/log/httpd
+ proxycachedir: ${localstatedir}/cache/httpd
+-
+-
+-# Layout used in Fedora httpd packaging.
+-
+- prefix: /usr
+- exec_prefix: ${prefix}
+- bindir: ${prefix}/bin
+- sbindir: ${prefix}/sbin
+- libdir: ${prefix}/lib
+- libexecdir: ${prefix}/libexec
+- mandir: ${prefix}/man
+- sysconfdir: /etc/httpd/conf
+- datadir: ${prefix}/share/httpd
+- installbuilddir: ${libdir}/httpd/build
+- errordir: ${datadir}/error
+- iconsdir: ${datadir}/icons
+- htdocsdir: /var/www/html
+- manualdir: ${datadir}/manual
+- cgidir: /var/www/cgi-bin
+- includedir: ${prefix}/include/httpd
+- localstatedir: /var
+- runtimedir: /run/httpd
+- logfiledir: ${localstatedir}/log/httpd
+- proxycachedir: ${localstatedir}/cache/httpd/proxy
+-
++
+
+ # According to the /opt filesystem conventions
+
diff --git a/SOURCES/httpd-2.4.3-sslsninotreq.patch b/SOURCES/httpd-2.4.3-sslsninotreq.patch
deleted file mode 100644
index bdad486..0000000
--- a/SOURCES/httpd-2.4.3-sslsninotreq.patch
+++ /dev/null
@@ -1,83 +0,0 @@
-diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c
-index 15993f1..53ed6f1 100644
---- a/modules/ssl/ssl_engine_config.c
-+++ b/modules/ssl/ssl_engine_config.c
-@@ -55,6 +55,7 @@ SSLModConfigRec *ssl_config_global_create(server_rec *s)
- mc = (SSLModConfigRec *)apr_palloc(pool, sizeof(*mc));
- mc->pPool = pool;
- mc->bFixed = FALSE;
-+ mc->sni_required = FALSE;
-
- /*
- * initialize per-module configuration
-diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
-index bf1f0e4..a7523de 100644
---- a/modules/ssl/ssl_engine_init.c
-+++ b/modules/ssl/ssl_engine_init.c
-@@ -409,7 +409,7 @@
- /*
- * Configuration consistency checks
- */
-- if ((rv = ssl_init_CheckServers(base_server, ptemp)) != APR_SUCCESS) {
-+ if ((rv = ssl_init_CheckServers(mc, base_server, ptemp)) != APR_SUCCESS) {
- return rv;
- }
-
-@@ -1475,7 +1475,7 @@
- return APR_SUCCESS;
- }
-
--apr_status_t ssl_init_CheckServers(server_rec *base_server, apr_pool_t *p)
-+apr_status_t ssl_init_CheckServers(SSLModConfigRec *mc, server_rec *base_server, apr_pool_t *p)
- {
- server_rec *s;
- SSLSrvConfigRec *sc;
-@@ -1557,6 +1557,7 @@
- }
-
- if (conflict) {
-+ mc->sni_required = TRUE;
- ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, APLOGNO(01917)
- "Init: Name-based SSL virtual hosts require "
- "an OpenSSL version with support for TLS extensions "
-diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c
-index bc9e26b..2460f01 100644
---- a/modules/ssl/ssl_engine_kernel.c
-+++ b/modules/ssl/ssl_engine_kernel.c
-@@ -164,6 +164,7 @@
- server_rec *handshakeserver = sslconn->server;
- SSLSrvConfigRec *hssc = mySrvConfig(handshakeserver);
-
-+ if (myModConfig(r->server)->sni_required) {
- if ((servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) {
- /*
- * The SNI extension supplied a hostname. So don't accept requests
-@@ -206,6 +207,7 @@
- "which is required to access this server.
\n");
- return HTTP_FORBIDDEN;
- }
-+ }
- }
- #endif
- modssl_set_app_data2(ssl, r);
-diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h
-index 75fc0e3..31dbfa9 100644
---- a/modules/ssl/ssl_private.h
-+++ b/modules/ssl/ssl_private.h
-@@ -554,6 +554,7 @@ typedef struct {
- apr_global_mutex_t *stapling_cache_mutex;
- apr_global_mutex_t *stapling_refresh_mutex;
- #endif
-+ BOOL sni_required;
- } SSLModConfigRec;
-
- /** Structure representing configured filenames for certs and keys for
-@@ -786,7 +787,7 @@
- apr_status_t ssl_init_Engine(server_rec *, apr_pool_t *);
- apr_status_t ssl_init_ConfigureServer(server_rec *, apr_pool_t *, apr_pool_t *, SSLSrvConfigRec *,
- apr_array_header_t *);
--apr_status_t ssl_init_CheckServers(server_rec *, apr_pool_t *);
-+apr_status_t ssl_init_CheckServers(SSLModConfigRec *mc, server_rec *, apr_pool_t *);
- STACK_OF(X509_NAME)
- *ssl_init_FindCAList(server_rec *, apr_pool_t *, const char *, const char *);
- void ssl_init_Child(apr_pool_t *, server_rec *);
diff --git a/SOURCES/httpd-2.4.33-mddefault.patch b/SOURCES/httpd-2.4.33-mddefault.patch
new file mode 100644
index 0000000..9e82fb8
--- /dev/null
+++ b/SOURCES/httpd-2.4.33-mddefault.patch
@@ -0,0 +1,21 @@
+
+Override default.
+
+--- httpd-2.4.33/modules/md/mod_md_config.c.mddefault
++++ httpd-2.4.33/modules/md/mod_md_config.c
+@@ -54,10 +54,14 @@
+
+ #define DEF_VAL (-1)
+
++#ifndef MD_DEFAULT_STORE_DIR
++#define MD_DEFAULT_STORE_DIR "state/md"
++#endif
++
+ /* Default settings for the global conf */
+ static md_mod_conf_t defmc = {
+ NULL,
+- "md",
++ MD_DEFAULT_STORE_DIR,
+ NULL,
+ NULL,
+ 80,
diff --git a/SOURCES/httpd-2.4.34-CVE-2018-11763.patch b/SOURCES/httpd-2.4.34-CVE-2018-11763.patch
new file mode 100644
index 0000000..60bfcdc
--- /dev/null
+++ b/SOURCES/httpd-2.4.34-CVE-2018-11763.patch
@@ -0,0 +1,462 @@
+diff --git a/modules/http2/h2_session.c b/modules/http2/h2_session.c
+index 805d677..a1b31d2 100644
+--- a/modules/http2/h2_session.c
++++ b/modules/http2/h2_session.c
+@@ -235,6 +235,7 @@ static int on_data_chunk_recv_cb(nghttp2_session *ngh2, uint8_t flags,
+ stream = h2_session_stream_get(session, stream_id);
+ if (stream) {
+ status = h2_stream_recv_DATA(stream, flags, data, len);
++ dispatch_event(session, H2_SESSION_EV_STREAM_CHANGE, 0, "stream data rcvd");
+ }
+ else {
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03064)
+@@ -317,9 +318,9 @@ static int on_header_cb(nghttp2_session *ngh2, const nghttp2_frame *frame,
+ }
+
+ /**
+- * nghttp2 session has received a complete frame. Most, it uses
+- * for processing of internal state. HEADER and DATA frames however
+- * we need to handle ourself.
++ * nghttp2 session has received a complete frame. Most are used by nghttp2
++ * for processing of internal state. Some, like HEADER and DATA frames,
++ * we need to act on.
+ */
+ static int on_frame_recv_cb(nghttp2_session *ng2s,
+ const nghttp2_frame *frame,
+@@ -378,6 +379,9 @@ static int on_frame_recv_cb(nghttp2_session *ng2s,
+ "h2_stream(%ld-%d): WINDOW_UPDATE incr=%d",
+ session->id, (int)frame->hd.stream_id,
+ frame->window_update.window_size_increment);
++ if (nghttp2_session_want_write(session->ngh2)) {
++ dispatch_event(session, H2_SESSION_EV_FRAME_RCVD, 0, "window update");
++ }
+ break;
+ case NGHTTP2_RST_STREAM:
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03067)
+@@ -404,6 +408,12 @@ static int on_frame_recv_cb(nghttp2_session *ng2s,
+ frame->goaway.error_code, NULL);
+ }
+ break;
++ case NGHTTP2_SETTINGS:
++ if (APLOGctrace2(session->c)) {
++ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c,
++ H2_SSSN_MSG(session, "SETTINGS, len=%ld"), (long)frame->hd.length);
++ }
++ break;
+ default:
+ if (APLOGctrace2(session->c)) {
+ char buffer[256];
+@@ -415,7 +425,40 @@ static int on_frame_recv_cb(nghttp2_session *ng2s,
+ }
+ break;
+ }
+- return (APR_SUCCESS == rv)? 0 : NGHTTP2_ERR_PROTO;
++
++ if (session->state == H2_SESSION_ST_IDLE) {
++ /* We received a frame, but session is in state IDLE. That means the frame
++ * did not really progress any of the (possibly) open streams. It was a meta
++ * frame, e.g. SETTINGS/WINDOW_UPDATE/unknown/etc.
++ * Remember: IDLE means we cannot send because either there are no streams open or
++ * all open streams are blocked on exhausted WINDOWs for outgoing data.
++ * The more frames we receive that do not change this, the less interested we
++ * become in serving this connection. This is expressed in increasing "idle_delays".
++ * Eventually, the connection will timeout and we'll close it. */
++ session->idle_frames = H2MIN(session->idle_frames + 1, session->frames_received);
++ ap_log_cerror( APLOG_MARK, APLOG_TRACE2, 0, session->c,
++ H2_SSSN_MSG(session, "session has %ld idle frames"),
++ (long)session->idle_frames);
++ if (session->idle_frames > 10) {
++ apr_size_t busy_frames = H2MAX(session->frames_received - session->idle_frames, 1);
++ int idle_ratio = (int)(session->idle_frames / busy_frames);
++ if (idle_ratio > 100) {
++ session->idle_delay = apr_time_from_msec(H2MIN(1000, idle_ratio));
++ }
++ else if (idle_ratio > 10) {
++ session->idle_delay = apr_time_from_msec(10);
++ }
++ else if (idle_ratio > 1) {
++ session->idle_delay = apr_time_from_msec(1);
++ }
++ else {
++ session->idle_delay = 0;
++ }
++ }
++ }
++
++ if (APR_SUCCESS != rv) return NGHTTP2_ERR_PROTO;
++ return 0;
+ }
+
+ static int h2_session_continue_data(h2_session *session) {
+@@ -1603,23 +1646,57 @@ static void update_child_status(h2_session *session, int status, const char *msg
+
+ static void transit(h2_session *session, const char *action, h2_session_state nstate)
+ {
++ apr_time_t timeout;
++ int ostate, loglvl;
++ const char *s;
++
+ if (session->state != nstate) {
+- int loglvl = APLOG_DEBUG;
+- if ((session->state == H2_SESSION_ST_BUSY && nstate == H2_SESSION_ST_WAIT)
+- || (session->state == H2_SESSION_ST_WAIT && nstate == H2_SESSION_ST_BUSY)){
++ ostate = session->state;
++ session->state = nstate;
++
++ loglvl = APLOG_DEBUG;
++ if ((ostate == H2_SESSION_ST_BUSY && nstate == H2_SESSION_ST_WAIT)
++ || (ostate == H2_SESSION_ST_WAIT && nstate == H2_SESSION_ST_BUSY)){
+ loglvl = APLOG_TRACE1;
+ }
+ ap_log_cerror(APLOG_MARK, loglvl, 0, session->c,
+ H2_SSSN_LOG(APLOGNO(03078), session,
+ "transit [%s] -- %s --> [%s]"),
+- h2_session_state_str(session->state), action,
++ h2_session_state_str(ostate), action,
+ h2_session_state_str(nstate));
+- session->state = nstate;
++
+ switch (session->state) {
+ case H2_SESSION_ST_IDLE:
+- update_child_status(session, (session->open_streams == 0?
+- SERVER_BUSY_KEEPALIVE
+- : SERVER_BUSY_READ), "idle");
++ if (!session->remote.emitted_count) {
++ /* on fresh connections, with async mpm, do not return
++ * to mpm for a second. This gives the first request a better
++ * chance to arrive (und connection leaving IDLE state).
++ * If we return to mpm right away, this connection has the
++ * same chance of being cleaned up by the mpm as connections
++ * that already served requests - not fair. */
++ session->idle_sync_until = apr_time_now() + apr_time_from_sec(1);
++ s = "timeout";
++ timeout = H2MAX(session->s->timeout, session->s->keep_alive_timeout);
++ update_child_status(session, SERVER_BUSY_READ, "idle");
++ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c,
++ H2_SSSN_LOG("", session, "enter idle, timeout = %d sec"),
++ (int)apr_time_sec(H2MAX(session->s->timeout, session->s->keep_alive_timeout)));
++ }
++ else if (session->open_streams) {
++ s = "timeout";
++ timeout = session->s->keep_alive_timeout;
++ update_child_status(session, SERVER_BUSY_KEEPALIVE, "idle");
++ }
++ else {
++ /* normal keepalive setup */
++ s = "keepalive";
++ timeout = session->s->keep_alive_timeout;
++ update_child_status(session, SERVER_BUSY_KEEPALIVE, "idle");
++ }
++ session->idle_until = apr_time_now() + timeout;
++ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c,
++ H2_SSSN_LOG("", session, "enter idle, %s = %d sec"),
++ s, (int)apr_time_sec(timeout));
+ break;
+ case H2_SESSION_ST_DONE:
+ update_child_status(session, SERVER_CLOSING, "done");
+@@ -1726,8 +1803,6 @@ static void h2_session_ev_no_io(h2_session *session, int arg, const char *msg)
+ * This means we only wait for WINDOW_UPDATE from the
+ * client and can block on READ. */
+ transit(session, "no io (flow wait)", H2_SESSION_ST_IDLE);
+- session->idle_until = apr_time_now() + session->s->timeout;
+- session->keep_sync_until = session->idle_until;
+ /* Make sure we have flushed all previously written output
+ * so that the client will react. */
+ if (h2_conn_io_flush(&session->io) != APR_SUCCESS) {
+@@ -1738,12 +1813,7 @@ static void h2_session_ev_no_io(h2_session *session, int arg, const char *msg)
+ }
+ else if (session->local.accepting) {
+ /* When we have no streams, but accept new, switch to idle */
+- apr_time_t now = apr_time_now();
+ transit(session, "no io (keepalive)", H2_SESSION_ST_IDLE);
+- session->idle_until = (session->remote.emitted_count?
+- session->s->keep_alive_timeout :
+- session->s->timeout) + now;
+- session->keep_sync_until = now + apr_time_from_sec(1);
+ }
+ else {
+ /* We are no longer accepting new streams and there are
+@@ -1758,12 +1828,25 @@ static void h2_session_ev_no_io(h2_session *session, int arg, const char *msg)
+ }
+ }
+
+-static void h2_session_ev_data_read(h2_session *session, int arg, const char *msg)
++static void h2_session_ev_frame_rcvd(h2_session *session, int arg, const char *msg)
++{
++ switch (session->state) {
++ case H2_SESSION_ST_IDLE:
++ case H2_SESSION_ST_WAIT:
++ transit(session, "frame received", H2_SESSION_ST_BUSY);
++ break;
++ default:
++ /* nop */
++ break;
++ }
++}
++
++static void h2_session_ev_stream_change(h2_session *session, int arg, const char *msg)
+ {
+ switch (session->state) {
+ case H2_SESSION_ST_IDLE:
+ case H2_SESSION_ST_WAIT:
+- transit(session, "data read", H2_SESSION_ST_BUSY);
++ transit(session, "stream change", H2_SESSION_ST_BUSY);
+ break;
+ default:
+ /* nop */
+@@ -1803,16 +1886,6 @@ static void h2_session_ev_pre_close(h2_session *session, int arg, const char *ms
+ static void ev_stream_open(h2_session *session, h2_stream *stream)
+ {
+ h2_iq_append(session->in_process, stream->id);
+- switch (session->state) {
+- case H2_SESSION_ST_IDLE:
+- if (session->open_streams == 1) {
+- /* enter timeout, since we have a stream again */
+- session->idle_until = (session->s->timeout + apr_time_now());
+- }
+- break;
+- default:
+- break;
+- }
+ }
+
+ static void ev_stream_closed(h2_session *session, h2_stream *stream)
+@@ -1825,11 +1898,6 @@ static void ev_stream_closed(h2_session *session, h2_stream *stream)
+ }
+ switch (session->state) {
+ case H2_SESSION_ST_IDLE:
+- if (session->open_streams == 0) {
+- /* enter keepalive timeout, since we no longer have streams */
+- session->idle_until = (session->s->keep_alive_timeout
+- + apr_time_now());
+- }
+ break;
+ default:
+ break;
+@@ -1887,6 +1955,7 @@ static void on_stream_state_enter(void *ctx, h2_stream *stream)
+ default:
+ break;
+ }
++ dispatch_event(session, H2_SESSION_EV_STREAM_CHANGE, 0, "stream state change");
+ }
+
+ static void on_stream_event(void *ctx, h2_stream *stream,
+@@ -1945,8 +2014,8 @@ static void dispatch_event(h2_session *session, h2_session_event_t ev,
+ case H2_SESSION_EV_NO_IO:
+ h2_session_ev_no_io(session, arg, msg);
+ break;
+- case H2_SESSION_EV_DATA_READ:
+- h2_session_ev_data_read(session, arg, msg);
++ case H2_SESSION_EV_FRAME_RCVD:
++ h2_session_ev_frame_rcvd(session, arg, msg);
+ break;
+ case H2_SESSION_EV_NGH2_DONE:
+ h2_session_ev_ngh2_done(session, arg, msg);
+@@ -1957,6 +2026,9 @@ static void dispatch_event(h2_session *session, h2_session_event_t ev,
+ case H2_SESSION_EV_PRE_CLOSE:
+ h2_session_ev_pre_close(session, arg, msg);
+ break;
++ case H2_SESSION_EV_STREAM_CHANGE:
++ h2_session_ev_stream_change(session, arg, msg);
++ break;
+ default:
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c,
+ H2_SSSN_MSG(session, "unknown event %d"), ev);
+@@ -1990,13 +2062,15 @@ apr_status_t h2_session_process(h2_session *session, int async)
+ apr_status_t status = APR_SUCCESS;
+ conn_rec *c = session->c;
+ int rv, mpm_state, trace = APLOGctrace3(c);
+-
++ apr_time_t now;
++
+ if (trace) {
+ ap_log_cerror( APLOG_MARK, APLOG_TRACE3, status, c,
+ H2_SSSN_MSG(session, "process start, async=%d"), async);
+ }
+
+ while (session->state != H2_SESSION_ST_DONE) {
++ now = apr_time_now();
+ session->have_read = session->have_written = 0;
+
+ if (session->local.accepting
+@@ -2034,39 +2108,42 @@ apr_status_t h2_session_process(h2_session *session, int async)
+ break;
+
+ case H2_SESSION_ST_IDLE:
+- /* We trust our connection into the default timeout/keepalive
+- * handling of the core filters/mpm iff:
+- * - keep_sync_until is not set
+- * - we have an async mpm
+- * - we have no open streams to process
+- * - we are not sitting on a Upgrade: request
+- * - we already have seen at least one request
+- */
+- if (!session->keep_sync_until && async && !session->open_streams
+- && !session->r && session->remote.emitted_count) {
++ if (session->idle_until && (apr_time_now() + session->idle_delay) > session->idle_until) {
++ ap_log_cerror( APLOG_MARK, APLOG_TRACE1, status, c,
++ H2_SSSN_MSG(session, "idle, timeout reached, closing"));
++ if (session->idle_delay) {
++ apr_table_setn(session->c->notes, "short-lingering-close", "1");
++ }
++ dispatch_event(session, H2_SESSION_EV_CONN_TIMEOUT, 0, "timeout");
++ goto out;
++ }
++
++ if (session->idle_delay) {
++ /* we are less interested in spending time on this connection */
++ ap_log_cerror( APLOG_MARK, APLOG_TRACE2, status, c,
++ H2_SSSN_MSG(session, "session is idle (%ld ms), idle wait %ld sec left"),
++ (long)apr_time_as_msec(session->idle_delay),
++ (long)apr_time_sec(session->idle_until - now));
++ apr_sleep(session->idle_delay);
++ session->idle_delay = 0;
++ }
++
++ h2_conn_io_flush(&session->io);
++ if (async && !session->r && (now > session->idle_sync_until)) {
+ if (trace) {
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, c,
+ H2_SSSN_MSG(session,
+ "nonblock read, %d streams open"),
+ session->open_streams);
+ }
+- h2_conn_io_flush(&session->io);
+ status = h2_session_read(session, 0);
+
+ if (status == APR_SUCCESS) {
+ session->have_read = 1;
+- dispatch_event(session, H2_SESSION_EV_DATA_READ, 0, NULL);
+ }
+- else if (APR_STATUS_IS_EAGAIN(status)
+- || APR_STATUS_IS_TIMEUP(status)) {
+- if (apr_time_now() > session->idle_until) {
+- dispatch_event(session,
+- H2_SESSION_EV_CONN_TIMEOUT, 0, NULL);
+- }
+- else {
+- status = APR_EAGAIN;
+- goto out;
+- }
++ else if (APR_STATUS_IS_EAGAIN(status) || APR_STATUS_IS_TIMEUP(status)) {
++ status = APR_EAGAIN;
++ goto out;
+ }
+ else {
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c,
+@@ -2078,7 +2155,6 @@ apr_status_t h2_session_process(h2_session *session, int async)
+ }
+ else {
+ /* make certain, we send everything before we idle */
+- h2_conn_io_flush(&session->io);
+ if (trace) {
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, c,
+ H2_SSSN_MSG(session,
+@@ -2090,7 +2166,6 @@ apr_status_t h2_session_process(h2_session *session, int async)
+ */
+ status = h2_mplx_idle(session->mplx);
+ if (status == APR_EAGAIN) {
+- dispatch_event(session, H2_SESSION_EV_DATA_READ, 0, NULL);
+ break;
+ }
+ else if (status != APR_SUCCESS) {
+@@ -2101,33 +2176,11 @@ apr_status_t h2_session_process(h2_session *session, int async)
+ status = h2_session_read(session, 1);
+ if (status == APR_SUCCESS) {
+ session->have_read = 1;
+- dispatch_event(session, H2_SESSION_EV_DATA_READ, 0, NULL);
+ }
+ else if (status == APR_EAGAIN) {
+ /* nothing to read */
+ }
+ else if (APR_STATUS_IS_TIMEUP(status)) {
+- apr_time_t now = apr_time_now();
+- if (now > session->keep_sync_until) {
+- /* if we are on an async mpm, now is the time that
+- * we may dare to pass control to it. */
+- session->keep_sync_until = 0;
+- }
+- if (now > session->idle_until) {
+- if (trace) {
+- ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, c,
+- H2_SSSN_MSG(session,
+- "keepalive timeout"));
+- }
+- dispatch_event(session,
+- H2_SESSION_EV_CONN_TIMEOUT, 0, "timeout");
+- }
+- else if (trace) {
+- ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, c,
+- H2_SSSN_MSG(session,
+- "keepalive, %f sec left"),
+- (session->idle_until - now) / 1000000.0f);
+- }
+ /* continue reading handling */
+ }
+ else if (APR_STATUS_IS_ECONNABORTED(status)
+@@ -2145,6 +2198,18 @@ apr_status_t h2_session_process(h2_session *session, int async)
+ dispatch_event(session, H2_SESSION_EV_CONN_ERROR, 0, "error");
+ }
+ }
++ if (nghttp2_session_want_write(session->ngh2)) {
++ ap_update_child_status(session->c->sbh, SERVER_BUSY_WRITE, NULL);
++ status = h2_session_send(session);
++ if (status == APR_SUCCESS) {
++ status = h2_conn_io_flush(&session->io);
++ }
++ if (status != APR_SUCCESS) {
++ dispatch_event(session, H2_SESSION_EV_CONN_ERROR,
++ H2_ERR_INTERNAL_ERROR, "writing");
++ break;
++ }
++ }
+ break;
+
+ case H2_SESSION_ST_BUSY:
+@@ -2154,7 +2219,6 @@ apr_status_t h2_session_process(h2_session *session, int async)
+ status = h2_session_read(session, 0);
+ if (status == APR_SUCCESS) {
+ session->have_read = 1;
+- dispatch_event(session, H2_SESSION_EV_DATA_READ, 0, NULL);
+ }
+ else if (status == APR_EAGAIN) {
+ /* nothing to read */
+@@ -2218,7 +2282,7 @@ apr_status_t h2_session_process(h2_session *session, int async)
+ session->iowait);
+ if (status == APR_SUCCESS) {
+ session->wait_us = 0;
+- dispatch_event(session, H2_SESSION_EV_DATA_READ, 0, NULL);
++ dispatch_event(session, H2_SESSION_EV_STREAM_CHANGE, 0, NULL);
+ }
+ else if (APR_STATUS_IS_TIMEUP(status)) {
+ /* go back to checking all inputs again */
+diff --git a/modules/http2/h2_session.h b/modules/http2/h2_session.h
+index 486938b..452c182 100644
+--- a/modules/http2/h2_session.h
++++ b/modules/http2/h2_session.h
+@@ -66,10 +66,11 @@ typedef enum {
+ H2_SESSION_EV_PROTO_ERROR, /* protocol error */
+ H2_SESSION_EV_CONN_TIMEOUT, /* connection timeout */
+ H2_SESSION_EV_NO_IO, /* nothing has been read or written */
+- H2_SESSION_EV_DATA_READ, /* connection data has been read */
++ H2_SESSION_EV_FRAME_RCVD, /* a frame has been received */
+ H2_SESSION_EV_NGH2_DONE, /* nghttp2 wants neither read nor write anything */
+ H2_SESSION_EV_MPM_STOPPING, /* the process is stopping */
+ H2_SESSION_EV_PRE_CLOSE, /* connection will close after this */
++ H2_SESSION_EV_STREAM_CHANGE, /* a stream (state/input/output) changed */
+ } h2_session_event_t;
+
+ typedef struct h2_session {
+@@ -118,8 +119,10 @@ typedef struct h2_session {
+ apr_size_t max_stream_mem; /* max buffer memory for a single stream */
+
+ apr_time_t idle_until; /* Time we shut down due to sheer boredom */
+- apr_time_t keep_sync_until; /* Time we sync wait until passing to async mpm */
+-
++ apr_time_t idle_sync_until; /* Time we sync wait until keepalive handling kicks in */
++ apr_size_t idle_frames; /* number of rcvd frames that kept session in idle state */
++ apr_interval_time_t idle_delay; /* Time we delay processing rcvd frames in idle state */
++
+ apr_bucket_brigade *bbtmp; /* brigade for keeping temporary data */
+ struct apr_thread_cond_t *iowait; /* our cond when trywaiting for data */
+
diff --git a/SOURCES/httpd-2.4.34-apr-escape.patch b/SOURCES/httpd-2.4.34-apr-escape.patch
new file mode 100644
index 0000000..3d8a401
--- /dev/null
+++ b/SOURCES/httpd-2.4.34-apr-escape.patch
@@ -0,0 +1,24 @@
+diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c
+index e0ccc31..c6c7e89 100644
+--- a/modules/proxy/mod_proxy_balancer.c
++++ b/modules/proxy/mod_proxy_balancer.c
+@@ -22,7 +22,7 @@
+ #include "apr_version.h"
+ #include "ap_hooks.h"
+ #include "apr_date.h"
+-#include "apr_escape.h"
++#include "util_md5.h"
+ #include "mod_watchdog.h"
+
+ static const char *balancer_mutex_type = "proxy-balancer-shm";
+@@ -774,9 +774,8 @@ static apr_status_t lock_remove(void *data)
+ }
+ }
+ }
+- apr_md5_final(md5, &md5_ctx);
+
+- return apr_pescape_hex(p, md5, sizeof md5, 0);
++ return ap_md5contextTo64(p, &md5_ctx);
+ }
+
+ /*
diff --git a/SOURCES/httpd-2.4.34-export.patch b/SOURCES/httpd-2.4.34-export.patch
new file mode 100644
index 0000000..18cdafa
--- /dev/null
+++ b/SOURCES/httpd-2.4.34-export.patch
@@ -0,0 +1,22 @@
+
+There is no need to "suck in" the apr/apr-util symbols when using
+a shared libapr{,util}, it just bloats the symbol table; so don't.
+
+Upstream-HEAD: needed
+Upstream-2.0: omit
+Upstream-Status: EXPORT_DIRS change is conditional on using shared apr
+
+diff --git a/server/Makefile.in b/server/Makefile.in
+index 1fa3344..f635d76 100644
+--- a/server/Makefile.in
++++ b/server/Makefile.in
+@@ -60,9 +60,6 @@ export_files:
+ ls $$dir/*.h ; \
+ done; \
+ echo "$(top_srcdir)/server/mpm_fdqueue.h"; \
+- for dir in $(EXPORT_DIRS_APR); do \
+- ls $$dir/ap[ru].h $$dir/ap[ru]_*.h 2>/dev/null; \
+- done; \
+ ) | sed -e s,//,/,g | sort -u > $@
+
+ exports.c: export_files
diff --git a/SOURCES/httpd-2.4.34-r1836472.patch b/SOURCES/httpd-2.4.34-r1836472.patch
new file mode 100644
index 0000000..ff4e1c2
--- /dev/null
+++ b/SOURCES/httpd-2.4.34-r1836472.patch
@@ -0,0 +1,11 @@
+--- a/modules/ssl/ssl_engine_ocsp.c 2018/07/23 08:47:59 1836471
++++ b/modules/ssl/ssl_engine_ocsp.c 2018/07/23 08:54:29 1836472
+@@ -61,7 +61,7 @@
+ /* Use default responder URL if forced by configuration, else use
+ * certificate-specified responder, falling back to default if
+ * necessary and possible. */
+- if (sc->server->ocsp_force_default) {
++ if (sc->server->ocsp_force_default == TRUE) {
+ s = sc->server->ocsp_responder;
+ }
+ else {
diff --git a/SOURCES/httpd-2.4.34-scl-libcurl.patch b/SOURCES/httpd-2.4.34-scl-libcurl.patch
new file mode 100644
index 0000000..11f6f88
--- /dev/null
+++ b/SOURCES/httpd-2.4.34-scl-libcurl.patch
@@ -0,0 +1,40 @@
+diff --git a/modules/md/config2.m4 b/modules/md/config2.m4
+index f154107..6a57dd4 100644
+--- a/modules/md/config2.m4
++++ b/modules/md/config2.m4
+@@ -52,12 +52,12 @@ AC_DEFUN([APACHE_CHECK_CURL],[
+ saved_PKG_CONFIG_PATH="$PKG_CONFIG_PATH"
+ AC_MSG_CHECKING([for pkg-config along $PKG_CONFIG_PATH])
+ if test "x$ap_curl_base" != "x" ; then
+- if test -f "${ap_curl_base}/lib/pkgconfig/libcurl.pc"; then
++ if test -f "${ap_curl_base}/lib/pkgconfig/httpd24-libcurl.pc"; then
+ dnl Ensure that the given path is used by pkg-config too, otherwise
+ dnl the system libcurl.pc might be picked up instead.
+ PKG_CONFIG_PATH="${ap_curl_base}/lib/pkgconfig${PKG_CONFIG_PATH+:}${PKG_CONFIG_PATH}"
+ export PKG_CONFIG_PATH
+- elif test -f "${ap_curl_base}/lib64/pkgconfig/libcurl.pc"; then
++ elif test -f "${ap_curl_base}/lib64/pkgconfig/httpd24-libcurl.pc"; then
+ dnl Ensure that the given path is used by pkg-config too, otherwise
+ dnl the system libcurl.pc might be picked up instead.
+ PKG_CONFIG_PATH="${ap_curl_base}/lib64/pkgconfig${PKG_CONFIG_PATH+:}${PKG_CONFIG_PATH}"
+@@ -69,16 +69,16 @@ AC_DEFUN([APACHE_CHECK_CURL],[
+ PKGCONFIG_LIBOPTS="--static"
+ fi
+ ])
+- ap_curl_libs="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-l --silence-errors libcurl`"
++ ap_curl_libs="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-l --silence-errors httpd24-libcurl`"
+ if test $? -eq 0; then
+ ap_curl_found="yes"
+- pkglookup="`$PKGCONFIG --cflags-only-I libcurl`"
++ pkglookup="`$PKGCONFIG --cflags-only-I httpd24-libcurl`"
+ APR_ADDTO(CPPFLAGS, [$pkglookup])
+ APR_ADDTO(MOD_CFLAGS, [$pkglookup])
+- pkglookup="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-L libcurl`"
++ pkglookup="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-L httpd24-libcurl`"
+ APR_ADDTO(LDFLAGS, [$pkglookup])
+ APR_ADDTO(MOD_LDFLAGS, [$pkglookup])
+- pkglookup="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-other libcurl`"
++ pkglookup="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-other httpd24-libcurl`"
+ APR_ADDTO(LDFLAGS, [$pkglookup])
+ APR_ADDTO(MOD_LDFLAGS, [$pkglookup])
+ fi
diff --git a/SOURCES/httpd-2.4.34-scl-libnghttp2.patch b/SOURCES/httpd-2.4.34-scl-libnghttp2.patch
new file mode 100644
index 0000000..8fad28e
--- /dev/null
+++ b/SOURCES/httpd-2.4.34-scl-libnghttp2.patch
@@ -0,0 +1,40 @@
+diff --git a/modules/http2/config2.m4 b/modules/http2/config2.m4
+index e8cefe3..904e519 100644
+--- a/modules/http2/config2.m4
++++ b/modules/http2/config2.m4
+@@ -81,12 +81,12 @@ AC_DEFUN([APACHE_CHECK_NGHTTP2],[
+ saved_PKG_CONFIG_PATH="$PKG_CONFIG_PATH"
+ AC_MSG_CHECKING([for pkg-config along $PKG_CONFIG_PATH])
+ if test "x$ap_nghttp2_base" != "x" ; then
+- if test -f "${ap_nghttp2_base}/lib/pkgconfig/libnghttp2.pc"; then
++ if test -f "${ap_nghttp2_base}/lib/pkgconfig/httpd24-libnghttp2.pc"; then
+ dnl Ensure that the given path is used by pkg-config too, otherwise
+ dnl the system libnghttp2.pc might be picked up instead.
+ PKG_CONFIG_PATH="${ap_nghttp2_base}/lib/pkgconfig${PKG_CONFIG_PATH+:}${PKG_CONFIG_PATH}"
+ export PKG_CONFIG_PATH
+- elif test -f "${ap_nghttp2_base}/lib64/pkgconfig/libnghttp2.pc"; then
++ elif test -f "${ap_nghttp2_base}/lib64/pkgconfig/httpd24-libnghttp2.pc"; then
+ dnl Ensure that the given path is used by pkg-config too, otherwise
+ dnl the system libnghttp2.pc might be picked up instead.
+ PKG_CONFIG_PATH="${ap_nghttp2_base}/lib64/pkgconfig${PKG_CONFIG_PATH+:}${PKG_CONFIG_PATH}"
+@@ -98,16 +98,16 @@ AC_DEFUN([APACHE_CHECK_NGHTTP2],[
+ PKGCONFIG_LIBOPTS="--static"
+ fi
+ ])
+- ap_nghttp2_libs="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-l --silence-errors libnghttp2`"
++ ap_nghttp2_libs="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-l --silence-errors httpd24-libnghttp2`"
+ if test $? -eq 0; then
+ ap_nghttp2_found="yes"
+- pkglookup="`$PKGCONFIG --cflags-only-I libnghttp2`"
++ pkglookup="`$PKGCONFIG --cflags-only-I httpd24-libnghttp2`"
+ APR_ADDTO(CPPFLAGS, [$pkglookup])
+ APR_ADDTO(MOD_CFLAGS, [$pkglookup])
+- pkglookup="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-L libnghttp2`"
++ pkglookup="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-L httpd24-libnghttp2`"
+ APR_ADDTO(LDFLAGS, [$pkglookup])
+ APR_ADDTO(MOD_LDFLAGS, [$pkglookup])
+- pkglookup="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-other libnghttp2`"
++ pkglookup="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-other httpd24-libnghttp2`"
+ APR_ADDTO(LDFLAGS, [$pkglookup])
+ APR_ADDTO(MOD_LDFLAGS, [$pkglookup])
+ fi
diff --git a/SOURCES/httpd-2.4.34-skiplist.patch b/SOURCES/httpd-2.4.34-skiplist.patch
new file mode 100644
index 0000000..06e3efa
--- /dev/null
+++ b/SOURCES/httpd-2.4.34-skiplist.patch
@@ -0,0 +1,1021 @@
+diff --git a/server/mpm/event/config.m4 b/server/mpm/event/config.m4
+index c891c75..351f1ac 100644
+--- a/server/mpm/event/config.m4
++++ b/server/mpm/event/config.m4
+@@ -7,8 +7,6 @@ elif test $have_threaded_sig_graceful != yes; then
+ AC_MSG_RESULT(no - SIG_GRACEFUL cannot be used with a threaded MPM)
+ elif test $ac_cv_have_threadsafe_pollset != yes; then
+ AC_MSG_RESULT(no - APR_POLLSET_THREADSAFE is not supported)
+-elif test $apr_has_skiplist != yes; then
+- AC_MSG_RESULT(no - APR skiplist is not available, need APR 1.5.x or later)
+ else
+ AC_MSG_RESULT(yes)
+ APACHE_MPM_SUPPORTED(event, yes, yes)
+diff --git a/server/mpm/event/config3.m4 b/server/mpm/event/config3.m4
+index 09d3626..722dfcb 100644
+--- a/server/mpm/event/config3.m4
++++ b/server/mpm/event/config3.m4
+@@ -2,6 +2,6 @@ dnl ## XXX - Need a more thorough check of the proper flags to use
+
+ APACHE_SUBST(MOD_MPM_EVENT_LDADD)
+
+-APACHE_MPM_MODULE(event, $enable_mpm_event, event.lo,[
++APACHE_MPM_MODULE(event, $enable_mpm_event, event.lo apr_skiplist.lo, [
+ AC_CHECK_FUNCS(pthread_kill)
+ ], , [\$(MOD_MPM_EVENT_LDADD)])
+diff --git a/server/mpm/event/apr_skiplist.c b/server/mpm/event/apr_skiplist.c
+new file mode 100644
+index 0000000..b4696bd
+--- /dev/null
++++ b/server/mpm/event/apr_skiplist.c
+@@ -0,0 +1,721 @@
++/* Licensed to the Apache Software Foundation (ASF) under one or more
++ * contributor license agreements. See the NOTICE file distributed with
++ * this work for additional information regarding copyright ownership.
++ * The ASF licenses this file to You under the Apache License, Version 2.0
++ * (the "License"); you may not use this file except in compliance with
++ * the License. You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++/*
++ * Modified to use APR and APR pools.
++ * TODO: Is malloc() better? Will long running skiplists grow too much?
++ * Keep the skiplist_alloc() and skiplist_free() until we know
++ * Yeah, if using pools it means some bogus cycles for checks
++ * (and an useless function call for skiplist_free) which we
++ * can removed if/when needed.
++ */
++
++#include "apr_skiplist.h"
++
++typedef struct {
++ apr_skiplistnode **data;
++ size_t size, pos;
++ apr_pool_t *p;
++} apr_skiplist_q;
++
++struct apr_skiplist {
++ apr_skiplist_compare compare;
++ apr_skiplist_compare comparek;
++ int height;
++ int preheight;
++ size_t size;
++ apr_skiplistnode *top;
++ apr_skiplistnode *bottom;
++ /* These two are needed for appending */
++ apr_skiplistnode *topend;
++ apr_skiplistnode *bottomend;
++ apr_skiplist *index;
++ apr_array_header_t *memlist;
++ apr_skiplist_q nodes_q,
++ stack_q;
++ apr_pool_t *pool;
++};
++
++struct apr_skiplistnode {
++ void *data;
++ apr_skiplistnode *next;
++ apr_skiplistnode *prev;
++ apr_skiplistnode *down;
++ apr_skiplistnode *up;
++ apr_skiplistnode *previndex;
++ apr_skiplistnode *nextindex;
++ apr_skiplist *sl;
++};
++
++static int get_b_rand(void)
++{
++ static int ph = 32; /* More bits than we will ever use */
++ static int randseq;
++ if (ph > 31) { /* Num bits in return of rand() */
++ ph = 0;
++ randseq = rand();
++ }
++ return randseq & (1 << ph++);
++}
++
++typedef struct {
++ size_t size;
++ apr_array_header_t *list;
++} memlist_t;
++
++typedef struct {
++ void *ptr;
++ char inuse;
++} chunk_t;
++
++APR_DECLARE(void *) apr_skiplist_alloc(apr_skiplist *sl, size_t size)
++{
++ if (sl->pool) {
++ void *ptr;
++ int found_size = 0;
++ int i;
++ chunk_t *newchunk;
++ memlist_t *memlist = (memlist_t *)sl->memlist->elts;
++ for (i = 0; i < sl->memlist->nelts; i++) {
++ if (memlist->size == size) {
++ int j;
++ chunk_t *chunk = (chunk_t *)memlist->list->elts;
++ found_size = 1;
++ for (j = 0; j < memlist->list->nelts; j++) {
++ if (!chunk->inuse) {
++ chunk->inuse = 1;
++ return chunk->ptr;
++ }
++ chunk++;
++ }
++ break; /* no free of this size; punt */
++ }
++ memlist++;
++ }
++ /* no free chunks */
++ ptr = apr_palloc(sl->pool, size);
++ if (!ptr) {
++ return ptr;
++ }
++ /*
++ * is this a new sized chunk? If so, we need to create a new
++ * array of them. Otherwise, re-use what we already have.
++ */
++ if (!found_size) {
++ memlist = apr_array_push(sl->memlist);
++ memlist->size = size;
++ memlist->list = apr_array_make(sl->pool, 20, sizeof(chunk_t));
++ }
++ newchunk = apr_array_push(memlist->list);
++ newchunk->ptr = ptr;
++ newchunk->inuse = 1;
++ return ptr;
++ }
++ else {
++ return malloc(size);
++ }
++}
++
++APR_DECLARE(void) apr_skiplist_free(apr_skiplist *sl, void *mem)
++{
++ if (!sl->pool) {
++ free(mem);
++ }
++ else {
++ int i;
++ memlist_t *memlist = (memlist_t *)sl->memlist->elts;
++ for (i = 0; i < sl->memlist->nelts; i++) {
++ int j;
++ chunk_t *chunk = (chunk_t *)memlist->list->elts;
++ for (j = 0; j < memlist->list->nelts; j++) {
++ if (chunk->ptr == mem) {
++ chunk->inuse = 0;
++ return;
++ }
++ chunk++;
++ }
++ memlist++;
++ }
++ }
++}
++
++static apr_status_t skiplist_qpush(apr_skiplist_q *q, apr_skiplistnode *m)
++{
++ if (q->pos >= q->size) {
++ apr_skiplistnode **data;
++ size_t size = (q->pos) ? q->pos * 2 : 32;
++ if (q->p) {
++ data = apr_palloc(q->p, size * sizeof(*data));
++ if (data) {
++ memcpy(data, q->data, q->pos * sizeof(*data));
++ }
++ }
++ else {
++ data = realloc(q->data, size * sizeof(*data));
++ }
++ if (!data) {
++ return APR_ENOMEM;
++ }
++ q->data = data;
++ q->size = size;
++ }
++ q->data[q->pos++] = m;
++ return APR_SUCCESS;
++}
++
++static APR_INLINE apr_skiplistnode *skiplist_qpop(apr_skiplist_q *q)
++{
++ return (q->pos > 0) ? q->data[--q->pos] : NULL;
++}
++
++static APR_INLINE void skiplist_qclear(apr_skiplist_q *q)
++{
++ q->pos = 0;
++}
++
++static apr_skiplistnode *skiplist_new_node(apr_skiplist *sl)
++{
++ apr_skiplistnode *m = skiplist_qpop(&sl->nodes_q);
++ if (!m) {
++ if (sl->pool) {
++ m = apr_palloc(sl->pool, sizeof *m);
++ }
++ else {
++ m = malloc(sizeof *m);
++ }
++ }
++ return m;
++}
++
++static apr_status_t skiplist_free_node(apr_skiplist *sl, apr_skiplistnode *m)
++{
++ return skiplist_qpush(&sl->nodes_q, m);
++}
++
++static apr_status_t skiplisti_init(apr_skiplist **s, apr_pool_t *p)
++{
++ apr_skiplist *sl;
++ if (p) {
++ sl = apr_pcalloc(p, sizeof(apr_skiplist));
++ sl->memlist = apr_array_make(p, 20, sizeof(memlist_t));
++ sl->pool = sl->nodes_q.p = sl->stack_q.p = p;
++ }
++ else {
++ sl = calloc(1, sizeof(apr_skiplist));
++ if (!sl) {
++ return APR_ENOMEM;
++ }
++ }
++ *s = sl;
++ return APR_SUCCESS;
++}
++
++static int indexing_comp(void *a, void *b)
++{
++ void *ac = (void *) (((apr_skiplist *) a)->compare);
++ void *bc = (void *) (((apr_skiplist *) b)->compare);
++ return ((ac < bc) ? -1 : ((ac > bc) ? 1 : 0));
++}
++
++static int indexing_compk(void *ac, void *b)
++{
++ void *bc = (void *) (((apr_skiplist *) b)->compare);
++ return ((ac < bc) ? -1 : ((ac > bc) ? 1 : 0));
++}
++
++APR_DECLARE(apr_status_t) apr_skiplist_init(apr_skiplist **s, apr_pool_t *p)
++{
++ apr_skiplist *sl;
++ skiplisti_init(s, p);
++ sl = *s;
++ skiplisti_init(&(sl->index), p);
++ apr_skiplist_set_compare(sl->index, indexing_comp, indexing_compk);
++ return APR_SUCCESS;
++}
++
++APR_DECLARE(void) apr_skiplist_set_compare(apr_skiplist *sl,
++ apr_skiplist_compare comp,
++ apr_skiplist_compare compk)
++{
++ if (sl->compare && sl->comparek) {
++ apr_skiplist_add_index(sl, comp, compk);
++ }
++ else {
++ sl->compare = comp;
++ sl->comparek = compk;
++ }
++}
++
++APR_DECLARE(void) apr_skiplist_add_index(apr_skiplist *sl,
++ apr_skiplist_compare comp,
++ apr_skiplist_compare compk)
++{
++ apr_skiplistnode *m;
++ apr_skiplist *ni;
++ int icount = 0;
++ apr_skiplist_find(sl->index, (void *)comp, &m);
++ if (m) {
++ return; /* Index already there! */
++ }
++ skiplisti_init(&ni, sl->pool);
++ apr_skiplist_set_compare(ni, comp, compk);
++ /* Build the new index... This can be expensive! */
++ m = apr_skiplist_insert(sl->index, ni);
++ while (m->prev) {
++ m = m->prev;
++ icount++;
++ }
++ for (m = apr_skiplist_getlist(sl); m; apr_skiplist_next(sl, &m)) {
++ int j = icount - 1;
++ apr_skiplistnode *nsln;
++ nsln = apr_skiplist_insert(ni, m->data);
++ /* skip from main index down list */
++ while (j > 0) {
++ m = m->nextindex;
++ j--;
++ }
++ /* insert this node in the indexlist after m */
++ nsln->nextindex = m->nextindex;
++ if (m->nextindex) {
++ m->nextindex->previndex = nsln;
++ }
++ nsln->previndex = m;
++ m->nextindex = nsln;
++ }
++}
++
++static int skiplisti_find_compare(apr_skiplist *sl, void *data,
++ apr_skiplistnode **ret,
++ apr_skiplist_compare comp)
++{
++ int count = 0;
++ apr_skiplistnode *m;
++ m = sl->top;
++ while (m) {
++ if (m->next) {
++ int compared = comp(data, m->next->data);
++ if (compared == 0) {
++ m = m->next;
++ while (m->down) {
++ m = m->down;
++ }
++ *ret = m;
++ return count;
++ }
++ if (compared > 0) {
++ m = m->next;
++ count++;
++ continue;
++ }
++ }
++ m = m->down;
++ count++;
++ }
++ *ret = NULL;
++ return count;
++}
++
++APR_DECLARE(void *) apr_skiplist_find_compare(apr_skiplist *sli, void *data,
++ apr_skiplistnode **iter,
++ apr_skiplist_compare comp)
++{
++ apr_skiplistnode *m;
++ apr_skiplist *sl;
++ if (!comp) {
++ if (iter) {
++ *iter = NULL;
++ }
++ return NULL;
++ }
++ if (comp == sli->compare || !sli->index) {
++ sl = sli;
++ }
++ else {
++ apr_skiplist_find(sli->index, (void *)comp, &m);
++ if (!m) {
++ if (iter) {
++ *iter = NULL;
++ }
++ return NULL;
++ }
++ sl = (apr_skiplist *) m->data;
++ }
++ skiplisti_find_compare(sl, data, &m, sl->comparek);
++ if (iter) {
++ *iter = m;
++ }
++ return (m) ? m->data : NULL;
++}
++
++APR_DECLARE(void *) apr_skiplist_find(apr_skiplist *sl, void *data, apr_skiplistnode **iter)
++{
++ return apr_skiplist_find_compare(sl, data, iter, sl->compare);
++}
++
++
++APR_DECLARE(apr_skiplistnode *) apr_skiplist_getlist(apr_skiplist *sl)
++{
++ if (!sl->bottom) {
++ return NULL;
++ }
++ return sl->bottom->next;
++}
++
++APR_DECLARE(void *) apr_skiplist_next(apr_skiplist *sl, apr_skiplistnode **iter)
++{
++ if (!*iter) {
++ return NULL;
++ }
++ *iter = (*iter)->next;
++ return (*iter) ? ((*iter)->data) : NULL;
++}
++
++APR_DECLARE(void *) apr_skiplist_previous(apr_skiplist *sl, apr_skiplistnode **iter)
++{
++ if (!*iter) {
++ return NULL;
++ }
++ *iter = (*iter)->prev;
++ return (*iter) ? ((*iter)->data) : NULL;
++}
++
++static APR_INLINE int skiplist_height(const apr_skiplist *sl)
++{
++ /* Skiplists (even empty) always have a top node, although this
++ * implementation defers its creation until the first insert, or
++ * deletes it with the last remove. We want the real height here.
++ */
++ return sl->height ? sl->height : 1;
++}
++
++APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert_compare(apr_skiplist *sl, void *data,
++ apr_skiplist_compare comp)
++{
++ apr_skiplistnode *m, *p, *tmp, *ret = NULL;
++ int ch, nh = 1;
++
++ if (!comp) {
++ return NULL;
++ }
++
++ ch = skiplist_height(sl);
++ if (sl->preheight) {
++ while (nh < sl->preheight && get_b_rand()) {
++ nh++;
++ }
++ }
++ else {
++ while (nh <= ch && get_b_rand()) {
++ nh++;
++ }
++ }
++
++ /* Now we have in nh the height at which we wish to insert our new node,
++ * and in ch the current height: don't create skip paths to the inserted
++ * element until the walk down through the tree (which decrements ch)
++ * reaches nh. From there, any walk down pushes the current node on a
++ * stack (the node(s) after which we would insert) to pop back through
++ * for insertion later.
++ */
++ m = sl->top;
++ while (m) {
++ if (m->next) {
++ int compared = comp(data, m->next->data);
++ if (compared == 0) {
++ /* Keep the existing element(s) */
++ skiplist_qclear(&sl->stack_q);
++ return NULL;
++ }
++ if (compared > 0) {
++ m = m->next;
++ continue;
++ }
++ }
++ if (ch <= nh) {
++ /* push on stack */
++ skiplist_qpush(&sl->stack_q, m);
++ }
++ m = m->down;
++ ch--;
++ }
++ /* Pop the stack and insert nodes */
++ p = NULL;
++ while ((m = skiplist_qpop(&sl->stack_q))) {
++ tmp = skiplist_new_node(sl);
++ tmp->next = m->next;
++ if (m->next) {
++ m->next->prev = tmp;
++ }
++ m->next = tmp;
++ tmp->prev = m;
++ tmp->up = NULL;
++ tmp->nextindex = tmp->previndex = NULL;
++ tmp->down = p;
++ if (p) {
++ p->up = tmp;
++ }
++ else {
++ /* This sets ret to the bottom-most node we are inserting */
++ ret = tmp;
++ }
++ tmp->data = data;
++ tmp->sl = sl;
++ p = tmp;
++ }
++
++ /* Now we are sure the node is inserted, grow our tree to 'nh' tall */
++ for (; sl->height < nh; sl->height++) {
++ m = skiplist_new_node(sl);
++ tmp = skiplist_new_node(sl);
++ m->up = m->prev = m->nextindex = m->previndex = NULL;
++ m->next = tmp;
++ m->down = sl->top;
++ m->data = NULL;
++ m->sl = sl;
++ if (sl->top) {
++ sl->top->up = m;
++ }
++ else {
++ sl->bottom = sl->bottomend = m;
++ }
++ sl->top = sl->topend = tmp->prev = m;
++ tmp->up = tmp->next = tmp->nextindex = tmp->previndex = NULL;
++ tmp->down = p;
++ tmp->data = data;
++ tmp->sl = sl;
++ if (p) {
++ p->up = tmp;
++ }
++ else {
++ /* This sets ret to the bottom-most node we are inserting */
++ ret = tmp;
++ }
++ p = tmp;
++ }
++ if (sl->index != NULL) {
++ /*
++ * this is a external insertion, we must insert into each index as
++ * well
++ */
++ apr_skiplistnode *ni, *li;
++ li = ret;
++ for (p = apr_skiplist_getlist(sl->index); p; apr_skiplist_next(sl->index, &p)) {
++ apr_skiplist *sli = (apr_skiplist *)p->data;
++ ni = apr_skiplist_insert_compare(sli, ret->data, sli->compare);
++ li->nextindex = ni;
++ ni->previndex = li;
++ li = ni;
++ }
++ }
++ sl->size++;
++ return ret;
++}
++
++APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert(apr_skiplist *sl, void *data)
++{
++ return apr_skiplist_insert_compare(sl, data, sl->compare);
++}
++
++#if 0
++void skiplist_print_struct(apr_skiplist * sl, char *prefix)
++{
++ apr_skiplistnode *p, *q;
++ fprintf(stderr, "Skiplist Structure (height: %d)\n", sl->height);
++ p = sl->bottom;
++ while (p) {
++ q = p;
++ fprintf(stderr, prefix);
++ while (q) {
++ fprintf(stderr, "%p ", q->data);
++ q = q->up;
++ }
++ fprintf(stderr, "\n");
++ p = p->next;
++ }
++}
++#endif
++
++static int skiplisti_remove(apr_skiplist *sl, apr_skiplistnode *m, apr_skiplist_freefunc myfree)
++{
++ apr_skiplistnode *p;
++ if (!m) {
++ return 0;
++ }
++ if (m->nextindex) {
++ skiplisti_remove(m->nextindex->sl, m->nextindex, NULL);
++ }
++ while (m->up) {
++ m = m->up;
++ }
++ while (m) {
++ p = m;
++ p->prev->next = p->next;/* take me out of the list */
++ if (p->next) {
++ p->next->prev = p->prev; /* take me out of the list */
++ }
++ m = m->down;
++ /* This only frees the actual data in the bottom one */
++ if (!m && myfree && p->data) {
++ myfree(p->data);
++ }
++ skiplist_free_node(sl, p);
++ }
++ sl->size--;
++ while (sl->top && sl->top->next == NULL) {
++ /* While the row is empty and we are not on the bottom row */
++ p = sl->top;
++ sl->top = sl->top->down;/* Move top down one */
++ if (sl->top) {
++ sl->top->up = NULL; /* Make it think its the top */
++ }
++ skiplist_free_node(sl, p);
++ sl->height--;
++ }
++ if (!sl->top) {
++ sl->bottom = sl->bottomend = NULL;
++ sl->topend = NULL;
++ }
++ return skiplist_height(sl);
++}
++
++APR_DECLARE(int) apr_skiplist_remove_compare(apr_skiplist *sli,
++ void *data,
++ apr_skiplist_freefunc myfree, apr_skiplist_compare comp)
++{
++ apr_skiplistnode *m;
++ apr_skiplist *sl;
++ if (!comp) {
++ return 0;
++ }
++ if (comp == sli->comparek || !sli->index) {
++ sl = sli;
++ }
++ else {
++ apr_skiplist_find(sli->index, (void *)comp, &m);
++ if (!m) {
++ return 0;
++ }
++ sl = (apr_skiplist *) m->data;
++ }
++ skiplisti_find_compare(sl, data, &m, comp);
++ if (!m) {
++ return 0;
++ }
++ while (m->previndex) {
++ m = m->previndex;
++ }
++ return skiplisti_remove(sl, m, myfree);
++}
++
++APR_DECLARE(int) apr_skiplist_remove(apr_skiplist *sl, void *data, apr_skiplist_freefunc myfree)
++{
++ return apr_skiplist_remove_compare(sl, data, myfree, sl->comparek);
++}
++
++APR_DECLARE(void) apr_skiplist_remove_all(apr_skiplist *sl, apr_skiplist_freefunc myfree)
++{
++ /*
++ * This must remove even the place holder nodes (bottom though top)
++ * because we specify in the API that one can free the Skiplist after
++ * making this call without memory leaks
++ */
++ apr_skiplistnode *m, *p, *u;
++ m = sl->bottom;
++ while (m) {
++ p = m->next;
++ if (myfree && p && p->data) {
++ myfree(p->data);
++ }
++ do {
++ u = m->up;
++ skiplist_free_node(sl, m);
++ m = u;
++ } while (m);
++ m = p;
++ }
++ sl->top = sl->bottom = NULL;
++ sl->topend = sl->bottomend = NULL;
++ sl->height = 0;
++ sl->size = 0;
++}
++
++APR_DECLARE(void *) apr_skiplist_pop(apr_skiplist *a, apr_skiplist_freefunc myfree)
++{
++ apr_skiplistnode *sln;
++ void *data = NULL;
++ sln = apr_skiplist_getlist(a);
++ if (sln) {
++ data = sln->data;
++ skiplisti_remove(a, sln, myfree);
++ }
++ return data;
++}
++
++APR_DECLARE(void *) apr_skiplist_peek(apr_skiplist *a)
++{
++ apr_skiplistnode *sln;
++ sln = apr_skiplist_getlist(a);
++ if (sln) {
++ return sln->data;
++ }
++ return NULL;
++}
++
++static void skiplisti_destroy(void *vsl)
++{
++ apr_skiplist_destroy(vsl, NULL);
++}
++
++APR_DECLARE(void) apr_skiplist_destroy(apr_skiplist *sl, apr_skiplist_freefunc myfree)
++{
++ while (apr_skiplist_pop(sl->index, skiplisti_destroy) != NULL)
++ ;
++ apr_skiplist_remove_all(sl, myfree);
++ if (!sl->pool) {
++ while (sl->nodes_q.pos)
++ free(sl->nodes_q.data[--sl->nodes_q.pos]);
++ free(sl->nodes_q.data);
++ free(sl->stack_q.data);
++ free(sl);
++ }
++}
++
++APR_DECLARE(apr_skiplist *) apr_skiplist_merge(apr_skiplist *sl1, apr_skiplist *sl2)
++{
++ /* Check integrity! */
++ apr_skiplist temp;
++ struct apr_skiplistnode *b2;
++ if (sl1->bottomend == NULL || sl1->bottomend->prev == NULL) {
++ apr_skiplist_remove_all(sl1, NULL);
++ temp = *sl1;
++ *sl1 = *sl2;
++ *sl2 = temp;
++ /* swap them so that sl2 can be freed normally upon return. */
++ return sl1;
++ }
++ if(sl2->bottom == NULL || sl2->bottom->next == NULL) {
++ apr_skiplist_remove_all(sl2, NULL);
++ return sl1;
++ }
++ /* This is what makes it brute force... Just insert :/ */
++ b2 = apr_skiplist_getlist(sl2);
++ while (b2) {
++ apr_skiplist_insert(sl1, b2->data);
++ apr_skiplist_next(sl2, &b2);
++ }
++ apr_skiplist_remove_all(sl2, NULL);
++ return sl1;
++}
+diff --git a/server/mpm/event/apr_skiplist.h b/server/mpm/event/apr_skiplist.h
+new file mode 100644
+index 0000000..f56ff22
+--- /dev/null
++++ b/server/mpm/event/apr_skiplist.h
+@@ -0,0 +1,263 @@
++/* Licensed to the Apache Software Foundation (ASF) under one or more
++ * contributor license agreements. See the NOTICE file distributed with
++ * this work for additional information regarding copyright ownership.
++ * The ASF licenses this file to You under the Apache License, Version 2.0
++ * (the "License"); you may not use this file except in compliance with
++ * the License. You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#ifndef APR_SKIPLIST_H
++#define APR_SKIPLIST_H
++/**
++ * @file apr_skiplist.h
++ * @brief APR skip list implementation
++ */
++
++#include "apr.h"
++#include "apr_portable.h"
++#include
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++/**
++ * @defgroup apr_skiplist Skip list implementation
++ * Refer to http://en.wikipedia.org/wiki/Skip_list for information
++ * about the purpose of and ideas behind skip lists.
++ * @ingroup APR
++ * @{
++ */
++
++/**
++ * apr_skiplist_compare is the function type that must be implemented
++ * per object type that is used in a skip list for comparisons to maintain
++ * order. A value <0 indicates placement after this node; a value of 0
++ * indicates collision with this exact node; a value >0 indicates placement
++ * before this node.
++ * */
++typedef int (*apr_skiplist_compare) (void *, void *);
++
++/**
++ * apr_skiplist_freefunc is the function type that must be implemented
++ * to handle elements as they are removed from a skip list.
++ */
++typedef void (*apr_skiplist_freefunc) (void *);
++
++/** Opaque structure used to represent the skip list */
++struct apr_skiplist;
++/** Opaque structure used to represent the skip list */
++typedef struct apr_skiplist apr_skiplist;
++
++/**
++ * Opaque structure used to represent abstract nodes in the skip list
++ * (an abstraction above the raw elements which are collected in the
++ * skip list).
++ */
++struct apr_skiplistnode;
++/** Opaque structure */
++typedef struct apr_skiplistnode apr_skiplistnode;
++
++/**
++ * Allocate memory using the same mechanism as the skip list.
++ * @param sl The skip list
++ * @param size The amount to allocate
++ * @remark If a pool was provided to apr_skiplist_init(), memory will
++ * be allocated from the pool or from a free list maintained with
++ * the skip list. Otherwise, memory will be allocated using the
++ * C standard library heap functions.
++ */
++APR_DECLARE(void *) apr_skiplist_alloc(apr_skiplist *sl, size_t size);
++
++/**
++ * Free memory using the same mechanism as the skip list.
++ * @param sl The skip list
++ * @param mem The object to free
++ * @remark If a pool was provided to apr_skiplist_init(), memory will
++ * be added to a free list maintained with the skip list and be available
++ * to operations on the skip list or to other calls to apr_skiplist_alloc().
++ * Otherwise, memory will be freed using the C standard library heap
++ * functions.
++ */
++APR_DECLARE(void) apr_skiplist_free(apr_skiplist *sl, void *mem);
++
++/**
++ * Allocate a new skip list
++ * @param sl The pointer in which to return the newly created skip list
++ * @param p The pool from which to allocate the skip list (optional).
++ * @remark Unlike most APR functions, a pool is optional. If no pool
++ * is provided, the C standard library heap functions will be used instead.
++ */
++APR_DECLARE(apr_status_t) apr_skiplist_init(apr_skiplist **sl, apr_pool_t *p);
++
++/**
++ * Set the comparison functions to be used for searching the skip list.
++ * @param sl The skip list
++ * @param XXX1 FIXME
++ * @param XXX2 FIXME
++ *
++ * @remark If existing comparison functions are being replaced, the index
++ * will be replaced during this call. That is a potentially expensive
++ * operation.
++ */
++APR_DECLARE(void) apr_skiplist_set_compare(apr_skiplist *sl, apr_skiplist_compare XXX1,
++ apr_skiplist_compare XXX2);
++
++/**
++ * Set the indexing functions to the specified comparison functions and
++ * rebuild the index.
++ * @param sl The skip list
++ * @param XXX1 FIXME
++ * @param XXX2 FIXME
++ *
++ * @remark If an index already exists, it will not be replaced and the
++ * comparison functions will not be changed.
++ */
++APR_DECLARE(void) apr_skiplist_add_index(apr_skiplist *sl, apr_skiplist_compare XXX1,
++ apr_skiplist_compare XXX2);
++
++/**
++ * Return the list maintained by the skip list abstraction.
++ * @param sl The skip list
++ */
++APR_DECLARE(apr_skiplistnode *) apr_skiplist_getlist(apr_skiplist *sl);
++
++/**
++ * Return the next matching element in the skip list using the specified
++ * comparison function.
++ * @param sl The skip list
++ * @param data The value to search for
++ * @param iter A pointer to the returned skip list node representing the element
++ * found
++ * @param func The comparison function to use
++ */
++APR_DECLARE(void *) apr_skiplist_find_compare(apr_skiplist *sl,
++ void *data,
++ apr_skiplistnode **iter,
++ apr_skiplist_compare func);
++
++/**
++ * Return the next matching element in the skip list using the current comparison
++ * function.
++ * @param sl The skip list
++ * @param data The value to search for
++ * @param iter A pointer to the returned skip list node representing the element
++ * found
++ */
++APR_DECLARE(void *) apr_skiplist_find(apr_skiplist *sl, void *data, apr_skiplistnode **iter);
++
++/**
++ * Return the next element in the skip list.
++ * @param sl The skip list
++ * @param iter On entry, a pointer to the skip list node to start with; on return,
++ * a pointer to the skip list node representing the element returned
++ * @remark If iter points to a NULL value on entry, NULL will be returned.
++ */
++APR_DECLARE(void *) apr_skiplist_next(apr_skiplist *sl, apr_skiplistnode **iter);
++
++/**
++ * Return the previous element in the skip list.
++ * @param sl The skip list
++ * @param iter On entry, a pointer to the skip list node to start with; on return,
++ * a pointer to the skip list node representing the element returned
++ * @remark If iter points to a NULL value on entry, NULL will be returned.
++ */
++APR_DECLARE(void *) apr_skiplist_previous(apr_skiplist *sl, apr_skiplistnode **iter);
++
++/**
++ * Insert an element into the skip list using the specified comparison function
++ * if it does not already exist.
++ * @param sl The skip list
++ * @param data The element to insert
++ * @param comp The comparison function to use for placement into the skip list
++ */
++APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert_compare(apr_skiplist *sl,
++ void *data, apr_skiplist_compare comp);
++
++/**
++ * Insert an element into the skip list using the existing comparison function
++ * if it does not already exist (as determined by the comparison function)
++ * @param sl The skip list
++ * @param data The element to insert
++ * @remark If no comparison function has been set for the skip list, the element
++ * will not be inserted and NULL will be returned.
++ */
++APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert(apr_skiplist* sl, void *data);
++
++/**
++ * Remove an element from the skip list using the specified comparison function for
++ * locating the element. In the case of duplicates, the 1st entry will be removed.
++ * @param sl The skip list
++ * @param data The element to remove
++ * @param myfree A function to be called for each removed element
++ * @param comp The comparison function to use for placement into the skip list
++ * @remark If the element is not found, 0 will be returned. Otherwise, the heightXXX
++ * will be returned.
++ */
++APR_DECLARE(int) apr_skiplist_remove_compare(apr_skiplist *sl, void *data,
++ apr_skiplist_freefunc myfree, apr_skiplist_compare comp);
++
++/**
++ * Remove an element from the skip list using the existing comparison function for
++ * locating the element. In the case of duplicates, the 1st entry will be removed.
++ * @param sl The skip list
++ * @param data The element to remove
++ * @param myfree A function to be called for each removed element
++ * @remark If the element is not found, 0 will be returned. Otherwise, the heightXXX
++ * will be returned.
++ * @remark If no comparison function has been set for the skip list, the element
++ * will not be removed and 0 will be returned.
++ */
++APR_DECLARE(int) apr_skiplist_remove(apr_skiplist *sl, void *data, apr_skiplist_freefunc myfree);
++
++/**
++ * Remove all elements from the skip list.
++ * @param sl The skip list
++ * @param myfree A function to be called for each removed element
++ */
++APR_DECLARE(void) apr_skiplist_remove_all(apr_skiplist *sl, apr_skiplist_freefunc myfree);
++
++/**
++ * Remove each element from the skip list.
++ * @param sl The skip list
++ * @param myfree A function to be called for each removed element
++ */
++APR_DECLARE(void) apr_skiplist_destroy(apr_skiplist *sl, apr_skiplist_freefunc myfree);
++
++/**
++ * Return the first element in the skip list, removing the element from the skip list.
++ * @param sl The skip list
++ * @param myfree A function to be called for the removed element
++ * @remark NULL will be returned if there are no elements
++ */
++APR_DECLARE(void *) apr_skiplist_pop(apr_skiplist *sl, apr_skiplist_freefunc myfree);
++
++/**
++ * Return the first element in the skip list, leaving the element in the skip list.
++ * @param sl The skip list
++ * @remark NULL will be returned if there are no elements
++ */
++APR_DECLARE(void *) apr_skiplist_peek(apr_skiplist *sl);
++
++/**
++ * Merge two skip lists. XXX SEMANTICS
++ * @param sl1 One of two skip lists to be merged
++ * @param sl2 The other of two skip lists to be merged
++ */
++APR_DECLARE(apr_skiplist *) apr_skiplist_merge(apr_skiplist *sl1, apr_skiplist *sl2);
++
++/** @} */
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* ! APR_SKIPLIST_H */
diff --git a/SOURCES/httpd-2.4.34-statements-comment.patch b/SOURCES/httpd-2.4.34-statements-comment.patch
new file mode 100644
index 0000000..97cd778
--- /dev/null
+++ b/SOURCES/httpd-2.4.34-statements-comment.patch
@@ -0,0 +1,16 @@
+diff --git a/modules/aaa/mod_access_compat.c b/modules/aaa/mod_access_compat.c
+index e9f1abe..b98bc05 100644
+--- a/modules/aaa/mod_access_compat.c
++++ b/modules/aaa/mod_access_compat.c
+@@ -152,6 +152,11 @@ static const char *allow_cmd(cmd_parms *cmd, void *dv, const char *from,
+ if (strcasecmp(from, "from"))
+ return "allow and deny must be followed by 'from'";
+
++ s = ap_strchr(where, '#');
++ if (s) {
++ *s = '\0';
++ }
++
+ a = (allowdeny *) apr_array_push(cmd->info ? d->allows : d->denys);
+ a->x.from = where;
+ a->limited = cmd->limited;
diff --git a/SOURCES/httpd-2.4.4-export.patch b/SOURCES/httpd-2.4.4-export.patch
deleted file mode 100644
index eb670c6..0000000
--- a/SOURCES/httpd-2.4.4-export.patch
+++ /dev/null
@@ -1,20 +0,0 @@
-
-There is no need to "suck in" the apr/apr-util symbols when using
-a shared libapr{,util}, it just bloats the symbol table; so don't.
-
-Upstream-HEAD: needed
-Upstream-2.0: omit
-Upstream-Status: EXPORT_DIRS change is conditional on using shared apr
-
---- httpd-2.4.4/server/Makefile.in.export
-+++ httpd-2.4.4/server/Makefile.in
-@@ -57,9 +57,6 @@ export_files:
- ( for dir in $(EXPORT_DIRS); do \
- ls $$dir/*.h ; \
- done; \
-- for dir in $(EXPORT_DIRS_APR); do \
-- ls $$dir/ap[ru].h $$dir/ap[ru]_*.h 2>/dev/null; \
-- done; \
- ) | sed -e s,//,/,g | sort -u > $@
-
- exports.c: export_files
diff --git a/SOURCES/httpd-2.4.4-mod_unique_id.patch b/SOURCES/httpd-2.4.4-mod_unique_id.patch
deleted file mode 100644
index 30bdfe0..0000000
--- a/SOURCES/httpd-2.4.4-mod_unique_id.patch
+++ /dev/null
@@ -1,239 +0,0 @@
---- trunk/modules/metadata/mod_unique_id.c 2011/12/02 23:02:04 1209766
-+++ trunk/modules/metadata/mod_unique_id.c 2013/07/10 16:20:31 1501827
-@@ -31,14 +31,11 @@
- #include "http_log.h"
- #include "http_protocol.h" /* for ap_hook_post_read_request */
-
--#if APR_HAVE_UNISTD_H
--#include /* for getpid() */
--#endif
-+#define ROOT_SIZE 10
-
- typedef struct {
- unsigned int stamp;
-- unsigned int in_addr;
-- unsigned int pid;
-+ char root[ROOT_SIZE];
- unsigned short counter;
- unsigned int thread_index;
- } unique_id_rec;
-@@ -64,20 +61,15 @@
- * gethostbyname (gethostname()) is unique across all the machines at the
- * "site".
- *
-- * We also further assume that pids fit in 32-bits. If something uses more
-- * than 32-bits, the fix is trivial, but it requires the unrolled uuencoding
-- * loop to be extended. * A similar fix is needed to support multithreaded
-- * servers, using a pid/tid combo.
-- *
-- * Together, the in_addr and pid are assumed to absolutely uniquely identify
-- * this one child from all other currently running children on all servers
-- * (including this physical server if it is running multiple httpds) from each
-+ * The root is assumed to absolutely uniquely identify this one child
-+ * from all other currently running children on all servers (including
-+ * this physical server if it is running multiple httpds) from each
- * other.
- *
-- * The stamp and counter are used to distinguish all hits for a particular
-- * (in_addr,pid) pair. The stamp is updated using r->request_time,
-- * saving cpu cycles. The counter is never reset, and is used to permit up to
-- * 64k requests in a single second by a single child.
-+ * The stamp and counter are used to distinguish all hits for a
-+ * particular root. The stamp is updated using r->request_time,
-+ * saving cpu cycles. The counter is never reset, and is used to
-+ * permit up to 64k requests in a single second by a single child.
- *
- * The 144-bits of unique_id_rec are encoded using the alphabet
- * [A-Za-z0-9@-], resulting in 24 bytes of printable characters. That is then
-@@ -92,7 +84,7 @@
- * module change.
- *
- * It is highly desirable that identifiers exist for "eternity". But future
-- * needs (such as much faster webservers, moving to 64-bit pids, or moving to a
-+ * needs (such as much faster webservers, or moving to a
- * multithreaded server) may dictate a need to change the contents of
- * unique_id_rec. Such a future implementation should ensure that the first
- * field is still a time_t stamp. By doing that, it is possible for a site to
-@@ -100,7 +92,15 @@
- * wait one entire second, and then start all of their new-servers. This
- * procedure will ensure that the new space of identifiers is completely unique
- * from the old space. (Since the first four unencoded bytes always differ.)
-+ *
-+ * Note: previous implementations used 32-bits of IP address plus pid
-+ * in place of the PRNG output in the "root" field. This was
-+ * insufficient for IPv6-only hosts, required working DNS to determine
-+ * a unique IP address (fragile), and needed a [0, 1) second sleep
-+ * call at startup to avoid pid reuse. Use of the PRNG avoids all
-+ * these issues.
- */
-+
- /*
- * Sun Jun 7 05:43:49 CEST 1998 -- Alvaro
- * More comments:
-@@ -116,8 +116,6 @@
- * htonl/ntohl. Well, this shouldn't be a problem till year 2106.
- */
-
--static unsigned global_in_addr;
--
- /*
- * XXX: We should have a per-thread counter and not use cur_unique_id.counter
- * XXX: in all threads, because this is bad for performance on multi-processor
-@@ -129,7 +127,7 @@
- /*
- * Number of elements in the structure unique_id_rec.
- */
--#define UNIQUE_ID_REC_MAX 5
-+#define UNIQUE_ID_REC_MAX 4
-
- static unsigned short unique_id_rec_offset[UNIQUE_ID_REC_MAX],
- unique_id_rec_size[UNIQUE_ID_REC_MAX],
-@@ -138,113 +136,32 @@
-
- static int unique_id_global_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *main_server)
- {
-- char str[APRMAXHOSTLEN + 1];
-- apr_status_t rv;
-- char *ipaddrstr;
-- apr_sockaddr_t *sockaddr;
--
- /*
- * Calculate the sizes and offsets in cur_unique_id.
- */
- unique_id_rec_offset[0] = APR_OFFSETOF(unique_id_rec, stamp);
- unique_id_rec_size[0] = sizeof(cur_unique_id.stamp);
-- unique_id_rec_offset[1] = APR_OFFSETOF(unique_id_rec, in_addr);
-- unique_id_rec_size[1] = sizeof(cur_unique_id.in_addr);
-- unique_id_rec_offset[2] = APR_OFFSETOF(unique_id_rec, pid);
-- unique_id_rec_size[2] = sizeof(cur_unique_id.pid);
-- unique_id_rec_offset[3] = APR_OFFSETOF(unique_id_rec, counter);
-- unique_id_rec_size[3] = sizeof(cur_unique_id.counter);
-- unique_id_rec_offset[4] = APR_OFFSETOF(unique_id_rec, thread_index);
-- unique_id_rec_size[4] = sizeof(cur_unique_id.thread_index);
-+ unique_id_rec_offset[1] = APR_OFFSETOF(unique_id_rec, root);
-+ unique_id_rec_size[1] = sizeof(cur_unique_id.root);
-+ unique_id_rec_offset[2] = APR_OFFSETOF(unique_id_rec, counter);
-+ unique_id_rec_size[2] = sizeof(cur_unique_id.counter);
-+ unique_id_rec_offset[3] = APR_OFFSETOF(unique_id_rec, thread_index);
-+ unique_id_rec_size[3] = sizeof(cur_unique_id.thread_index);
- unique_id_rec_total_size = unique_id_rec_size[0] + unique_id_rec_size[1] +
-- unique_id_rec_size[2] + unique_id_rec_size[3] +
-- unique_id_rec_size[4];
-+ unique_id_rec_size[2] + unique_id_rec_size[3];
-
- /*
- * Calculate the size of the structure when encoded.
- */
- unique_id_rec_size_uu = (unique_id_rec_total_size*8+5)/6;
-
-- /*
-- * Now get the global in_addr. Note that it is not sufficient to use one
-- * of the addresses from the main_server, since those aren't as likely to
-- * be unique as the physical address of the machine
-- */
-- if ((rv = apr_gethostname(str, sizeof(str) - 1, p)) != APR_SUCCESS) {
-- ap_log_error(APLOG_MARK, APLOG_ALERT, rv, main_server, APLOGNO(01563)
-- "unable to find hostname of the server");
-- return HTTP_INTERNAL_SERVER_ERROR;
-- }
--
-- if ((rv = apr_sockaddr_info_get(&sockaddr, str, AF_INET, 0, 0, p)) == APR_SUCCESS) {
-- global_in_addr = sockaddr->sa.sin.sin_addr.s_addr;
-- }
-- else {
-- ap_log_error(APLOG_MARK, APLOG_ALERT, rv, main_server, APLOGNO(01564)
-- "unable to find IPv4 address of \"%s\"", str);
--#if APR_HAVE_IPV6
-- if ((rv = apr_sockaddr_info_get(&sockaddr, str, AF_INET6, 0, 0, p)) == APR_SUCCESS) {
-- memcpy(&global_in_addr,
-- (char *)sockaddr->ipaddr_ptr + sockaddr->ipaddr_len - sizeof(global_in_addr),
-- sizeof(global_in_addr));
-- ap_log_error(APLOG_MARK, APLOG_ALERT, rv, main_server, APLOGNO(01565)
-- "using low-order bits of IPv6 address "
-- "as if they were unique");
-- }
-- else
--#endif
-- return HTTP_INTERNAL_SERVER_ERROR;
-- }
--
-- apr_sockaddr_ip_get(&ipaddrstr, sockaddr);
-- ap_log_error(APLOG_MARK, APLOG_INFO, 0, main_server, APLOGNO(01566) "using ip addr %s",
-- ipaddrstr);
--
-- /*
-- * If the server is pummelled with restart requests we could possibly end
-- * up in a situation where we're starting again during the same second
-- * that has been used in previous identifiers. Avoid that situation.
-- *
-- * In truth, for this to actually happen not only would it have to restart
-- * in the same second, but it would have to somehow get the same pids as
-- * one of the other servers that was running in that second. Which would
-- * mean a 64k wraparound on pids ... not very likely at all.
-- *
-- * But protecting against it is relatively cheap. We just sleep into the
-- * next second.
-- */
-- apr_sleep(apr_time_from_sec(1) - apr_time_usec(apr_time_now()));
- return OK;
- }
-
- static void unique_id_child_init(apr_pool_t *p, server_rec *s)
- {
-- pid_t pid;
--
-- /*
-- * Note that we use the pid because it's possible that on the same
-- * physical machine there are multiple servers (i.e. using Listen). But
-- * it's guaranteed that none of them will share the same pids between
-- * children.
-- *
-- * XXX: for multithread this needs to use a pid/tid combo and probably
-- * needs to be expanded to 32 bits
-- */
-- pid = getpid();
-- cur_unique_id.pid = pid;
--
-- /*
-- * Test our assumption that the pid is 32-bits. It's possible that
-- * 64-bit machines will declare pid_t to be 64 bits but only use 32
-- * of them. It would have been really nice to test this during
-- * global_init ... but oh well.
-- */
-- if ((pid_t)cur_unique_id.pid != pid) {
-- ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, APLOGNO(01567)
-- "oh no! pids are greater than 32-bits! I'm broken!");
-- }
--
-- cur_unique_id.in_addr = global_in_addr;
-+ ap_random_insecure_bytes(&cur_unique_id.root,
-+ sizeof(cur_unique_id.root));
-
- /*
- * If we use 0 as the initial counter we have a little less protection
-@@ -253,13 +170,6 @@
- */
- ap_random_insecure_bytes(&cur_unique_id.counter,
- sizeof(cur_unique_id.counter));
--
-- /*
-- * We must always use network ordering for these bytes, so that
-- * identifiers are comparable between machines of different byte
-- * orderings. Note in_addr is already in network order.
-- */
-- cur_unique_id.pid = htonl(cur_unique_id.pid);
- }
-
- /* NOTE: This is *NOT* the same encoding used by base64encode ... the last two
-@@ -291,10 +201,8 @@
- unsigned short counter;
- int i,j,k;
-
-- new_unique_id.in_addr = cur_unique_id.in_addr;
-- new_unique_id.pid = cur_unique_id.pid;
-+ memcpy(&new_unique_id.root, &cur_unique_id.root, ROOT_SIZE);
- new_unique_id.counter = cur_unique_id.counter;
--
- new_unique_id.stamp = htonl((unsigned int)apr_time_sec(r->request_time));
- new_unique_id.thread_index = htonl((unsigned int)r->connection->id);
-
diff --git a/SOURCES/httpd-2.4.4-r1337344+.patch b/SOURCES/httpd-2.4.4-r1337344+.patch
deleted file mode 100644
index 6e5c3e7..0000000
--- a/SOURCES/httpd-2.4.4-r1337344+.patch
+++ /dev/null
@@ -1,250 +0,0 @@
-# ./pullrev.sh 1337344 1341905 1342065 1341930
-
-suexec enhancements:
-
-1) use syslog for logging
-2) use capabilities not setuid/setgid root binary
-
-http://svn.apache.org/viewvc?view=revision&revision=1337344
-http://svn.apache.org/viewvc?view=revision&revision=1341905
-http://svn.apache.org/viewvc?view=revision&revision=1342065
-http://svn.apache.org/viewvc?view=revision&revision=1341930
-
---- httpd-2.4.4/configure.in.r1337344+
-+++ httpd-2.4.4/configure.in
-@@ -734,7 +734,24 @@ APACHE_HELP_STRING(--with-suexec-gidmin,
-
- AC_ARG_WITH(suexec-logfile,
- APACHE_HELP_STRING(--with-suexec-logfile,Set the logfile),[
-- AC_DEFINE_UNQUOTED(AP_LOG_EXEC, "$withval", [SuExec log file] ) ] )
-+ if test "x$withval" = "xyes"; then
-+ AC_DEFINE_UNQUOTED(AP_LOG_EXEC, "$withval", [SuExec log file])
-+ fi
-+])
-+
-+AC_ARG_WITH(suexec-syslog,
-+APACHE_HELP_STRING(--with-suexec-syslog,Set the logfile),[
-+ if test $withval = "yes"; then
-+ if test "x${with_suexec_logfile}" != "xno"; then
-+ AC_MSG_NOTICE([hint: use "--without-suexec-logfile --with-suexec-syslog"])
-+ AC_MSG_ERROR([suexec does not support both logging to file and syslog])
-+ fi
-+ AC_CHECK_FUNCS([vsyslog], [], [
-+ AC_MSG_ERROR([cannot support syslog from suexec without vsyslog()])])
-+ AC_DEFINE(AP_LOG_SYSLOG, 1, [SuExec log to syslog])
-+ fi
-+])
-+
-
- AC_ARG_WITH(suexec-safepath,
- APACHE_HELP_STRING(--with-suexec-safepath,Set the safepath),[
-@@ -744,6 +761,15 @@ AC_ARG_WITH(suexec-umask,
- APACHE_HELP_STRING(--with-suexec-umask,umask for suexec'd process),[
- AC_DEFINE_UNQUOTED(AP_SUEXEC_UMASK, 0$withval, [umask for suexec'd process] ) ] )
-
-+INSTALL_SUEXEC=setuid
-+AC_ARG_ENABLE([suexec-capabilities],
-+APACHE_HELP_STRING(--enable-suexec-capabilities,Use Linux capability bits not setuid root suexec), [
-+INSTALL_SUEXEC=caps
-+AC_DEFINE(AP_SUEXEC_CAPABILITIES, 1,
-+ [Enable if suexec is installed with Linux capabilities, not setuid])
-+])
-+APACHE_SUBST(INSTALL_SUEXEC)
-+
- dnl APR should go after the other libs, so the right symbols can be picked up
- if test x${apu_found} != xobsolete; then
- AP_LIBS="$AP_LIBS `$apu_config --avoid-ldap --link-libtool`"
---- httpd-2.4.4/docs/manual/suexec.html.en.r1337344+
-+++ httpd-2.4.4/docs/manual/suexec.html.en
-@@ -372,6 +372,21 @@
- together with the --enable-suexec
option to let
- APACI accept your request for using the suEXEC feature.
-
-+ --enable-suexec-capabilities
-+
-+ Linux specific: Normally,
-+ the suexec
binary is installed "setuid/setgid
-+ root", which allows it to run with the full privileges of the
-+ root user. If this option is used, the suexec
-+ binary will instead be installed with only the setuid/setgid
-+ "capability" bits set, which is the subset of full root
-+ priviliges required for suexec operation. Note that
-+ the suexec
binary may not be able to write to a log
-+ file in this mode; it is recommended that the
-+ --with-suexec-syslog --without-suexec-logfile
-+ options are used in conjunction with this mode, so that syslog
-+ logging is used instead.
-+
- --with-suexec-bin=PATH
-
- The path to the suexec
binary must be hard-coded
-@@ -433,6 +448,12 @@
- "suexec_log
" and located in your standard logfile
- directory (--logfiledir
).
-
-+ --with-suexec-syslog
-+
-+ If defined, suexec will log notices and errors to syslog
-+ instead of a logfile. This option must be combined
-+ with --without-suexec-logfile
.
-+
- --with-suexec-safepath=PATH
-
- Define a safe PATH environment to pass to CGI
-@@ -550,9 +571,12 @@ Group webgroup
-
- The suEXEC wrapper will write log information
- to the file defined with the --with-suexec-logfile
-- option as indicated above. If you feel you have configured and
-- installed the wrapper properly, have a look at this log and the
-- error_log for the server to see where you may have gone astray.
-+ option as indicated above, or to syslog if --with-suexec-syslog
-+ is used. If you feel you have configured and
-+ installed the wrapper properly, have a look at the log and the
-+ error_log for the server to see where you may have gone astray.
-+ The output of "suexec -V"
will show the options
-+ used to compile suexec, if using a binary distribution.
-
-
-
-@@ -640,4 +664,4 @@ if (typeof(prettyPrint) !== 'undefined')
- prettyPrint();
- }
- //-->
--