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.

- -
top
-
-@@ -640,4 +664,4 @@ if (typeof(prettyPrint) !== 'undefined') - prettyPrint(); - } - //--> -- -\ No newline at end of file -+ ---- httpd-2.4.4/Makefile.in.r1337344+ -+++ httpd-2.4.4/Makefile.in -@@ -238,11 +238,22 @@ install-man: - cd $(DESTDIR)$(manualdir) && find . -name ".svn" -type d -print | xargs rm -rf 2>/dev/null || true; \ - fi - --install-suexec: -+install-suexec: install-suexec-binary install-suexec-$(INSTALL_SUEXEC) -+ -+install-suexec-binary: - @if test -f $(builddir)/support/suexec; then \ - test -d $(DESTDIR)$(sbindir) || $(MKINSTALLDIRS) $(DESTDIR)$(sbindir); \ - $(INSTALL_PROGRAM) $(top_builddir)/support/suexec $(DESTDIR)$(sbindir); \ -- chmod 4755 $(DESTDIR)$(sbindir)/suexec; \ -+ fi -+ -+install-suexec-setuid: -+ @if test -f $(builddir)/support/suexec; then \ -+ chmod 4755 $(DESTDIR)$(sbindir)/suexec; \ -+ fi -+ -+install-suexec-caps: -+ @if test -f $(builddir)/support/suexec; then \ -+ setcap 'cap_setuid,cap_setgid+pe' $(DESTDIR)$(sbindir)/suexec; \ - fi - - suexec: ---- httpd-2.4.4/modules/arch/unix/mod_unixd.c.r1337344+ -+++ httpd-2.4.4/modules/arch/unix/mod_unixd.c -@@ -284,6 +284,13 @@ unixd_set_suexec(cmd_parms *cmd, void *d - return NULL; - } - -+#ifdef AP_SUEXEC_CAPABILITIES -+/* If suexec is using capabilities, don't test for the setuid bit. */ -+#define SETUID_TEST(finfo) (1) -+#else -+#define SETUID_TEST(finfo) (finfo.protection & APR_USETID) -+#endif -+ - static int - unixd_pre_config(apr_pool_t *pconf, apr_pool_t *plog, - apr_pool_t *ptemp) -@@ -300,7 +307,7 @@ unixd_pre_config(apr_pool_t *pconf, apr_ - ap_unixd_config.suexec_enabled = 0; - if ((apr_stat(&wrapper, SUEXEC_BIN, APR_FINFO_NORM, ptemp)) - == APR_SUCCESS) { -- if ((wrapper.protection & APR_USETID) && wrapper.user == 0 -+ if (SETUID_TEST(wrapper) && wrapper.user == 0 - && (access(SUEXEC_BIN, R_OK|X_OK) == 0)) { - ap_unixd_config.suexec_enabled = 1; - ap_unixd_config.suexec_disabled_reason = ""; ---- httpd-2.4.4/support/suexec.c.r1337344+ -+++ httpd-2.4.4/support/suexec.c -@@ -58,6 +58,10 @@ - #include - #endif - -+#ifdef AP_LOG_SYSLOG -+#include -+#endif -+ - #if defined(PATH_MAX) - #define AP_MAXPATH PATH_MAX - #elif defined(MAXPATHLEN) -@@ -69,7 +73,20 @@ - #define AP_ENVBUF 256 - - extern char **environ; -+ -+#ifdef AP_LOG_SYSLOG -+/* Syslog support. */ -+#if !defined(AP_LOG_FACILITY) && defined(LOG_AUTHPRIV) -+#define AP_LOG_FACILITY LOG_AUTHPRIV -+#elif !defined(AP_LOG_FACILITY) -+#define AP_LOG_FACILITY LOG_AUTH -+#endif -+ -+static int log_open; -+#else -+/* Non-syslog support. */ - static FILE *log = NULL; -+#endif - - static const char *const safe_env_lst[] = - { -@@ -137,7 +154,14 @@ static void err_output(int is_error, con - - static void err_output(int is_error, const char *fmt, va_list ap) - { --#ifdef AP_LOG_EXEC -+#if defined(AP_LOG_SYSLOG) -+ if (!log_open) { -+ openlog("suexec", LOG_PID, AP_LOG_FACILITY); -+ log_open = 1; -+ } -+ -+ vsyslog(is_error ? LOG_ERR : LOG_INFO, fmt, ap); -+#elif defined(AP_LOG_EXEC) - time_t timevar; - struct tm *lt; - -@@ -295,7 +319,9 @@ int main(int argc, char *argv[]) - #ifdef AP_HTTPD_USER - fprintf(stderr, " -D AP_HTTPD_USER=\"%s\"\n", AP_HTTPD_USER); - #endif --#ifdef AP_LOG_EXEC -+#if defined(AP_LOG_SYSLOG) -+ fprintf(stderr, " -D AP_LOG_SYSLOG\n"); -+#elif defined(AP_LOG_EXEC) - fprintf(stderr, " -D AP_LOG_EXEC=\"%s\"\n", AP_LOG_EXEC); - #endif - #ifdef AP_SAFE_PATH -@@ -591,6 +617,12 @@ int main(int argc, char *argv[]) - #endif /* AP_SUEXEC_UMASK */ - - /* Be sure to close the log file so the CGI can't mess with it. */ -+#ifdef AP_LOG_SYSLOG -+ if (log_open) { -+ closelog(); -+ log_open = 0; -+ } -+#else - if (log != NULL) { - #if APR_HAVE_FCNTL_H - /* -@@ -612,6 +644,7 @@ int main(int argc, char *argv[]) - log = NULL; - #endif - } -+#endif - - /* - * Execute the command, replacing our image with its own. diff --git a/SOURCES/httpd-2.4.6-ab-overflow.patch b/SOURCES/httpd-2.4.6-ab-overflow.patch deleted file mode 100644 index 91a76b2..0000000 --- a/SOURCES/httpd-2.4.6-ab-overflow.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- a/support/ab.c 2014/08/14 12:12:38 1617912 -+++ b/support/ab.c 2014/08/14 12:15:31 1617913 -@@ -1029,7 +1029,7 @@ - ap_round_ms(stats[done - 1].time)); - else - printf(" %d%% %5" APR_TIME_T_FMT "\n", percs[i], -- ap_round_ms(stats[(int) (done * percs[i] / 100)].time)); -+ ap_round_ms(stats[(unsigned long)done * percs[i] / 100].time)); - } - } - if (csvperc) { -@@ -1046,7 +1046,7 @@ - else if (i == 100) - t = ap_double_ms(stats[done - 1].time); - else -- t = ap_double_ms(stats[(int) (0.5 + done * i / 100.0)].time); -+ t = ap_double_ms(stats[(unsigned long) (0.5 + (double)done * i / 100.0)].time); - fprintf(out, "%d,%.3f\n", i, t); - } - fclose(out); diff --git a/SOURCES/httpd-2.4.6-ap-ipv6.patch b/SOURCES/httpd-2.4.6-ap-ipv6.patch deleted file mode 100644 index 87e0c1f..0000000 --- a/SOURCES/httpd-2.4.6-ap-ipv6.patch +++ /dev/null @@ -1,139 +0,0 @@ -diff --git a/support/ab.c b/support/ab.c -index f54c402..93c9066 100644 ---- a/support/ab.c -+++ b/support/ab.c -@@ -344,6 +344,7 @@ apr_time_t start, lasttime, stoptime; - char _request[8192]; - char *request = _request; - apr_size_t reqlen; -+int requests_initialized = 0; - - /* one global throw-away buffer to read stuff into */ - char buffer[8192]; -@@ -1253,12 +1254,18 @@ static void start_connect(struct connection * c) - else { - set_conn_state(c, STATE_UNCONNECTED); - apr_socket_close(c->aprsock); -- err_conn++; -- if (bad++ > 10) { -+ if (good == 0 && destsa->next) { -+ destsa = destsa->next; -+ err_conn = 0; -+ } -+ else if (bad++ > 10) { - fprintf(stderr, - "\nTest aborted after 10 failures\n\n"); - apr_err("apr_socket_connect()", rv); - } -+ else { -+ err_conn++; -+ } - - start_connect(c); - return; -@@ -1339,6 +1346,7 @@ static void read_connection(struct connection * c) - apr_status_t status; - char *part; - char respcode[4]; /* 3 digits and null */ -+ int i; - - r = sizeof(buffer); - #ifdef USE_SSL -@@ -1362,6 +1370,13 @@ static void read_connection(struct connection * c) - good++; - close_connection(c); - } -+ else if (scode == SSL_ERROR_SYSCALL -+ && c->read == 0 -+ && destsa->next -+ && c->state == STATE_CONNECTING -+ && good == 0) { -+ return; -+ } - else if (scode != SSL_ERROR_WANT_WRITE - && scode != SSL_ERROR_WANT_READ) { - /* some fatal error: */ -@@ -1387,8 +1402,8 @@ static void read_connection(struct connection * c) - } - /* catch legitimate fatal apr_socket_recv errors */ - else if (status != APR_SUCCESS) { -- err_recv++; - if (recverrok) { -+ err_recv++; - bad++; - close_connection(c); - if (verbosity >= 1) { -@@ -1396,7 +1411,12 @@ static void read_connection(struct connection * c) - fprintf(stderr,"%s: %s (%d)\n", "apr_socket_recv", apr_strerror(status, buf, sizeof buf), status); - } - return; -- } else { -+ } else if (destsa->next && c->state == STATE_CONNECTING -+ && c->read == 0 && good == 0) { -+ return; -+ } -+ else { -+ err_recv++; - apr_err("apr_socket_recv", status); - } - } -@@ -1523,6 +1543,16 @@ static void read_connection(struct connection * c) - } - c->bread += c->cbx - (s + l - c->cbuff) + r - tocopy; - totalbread += c->bread; -+ -+ /* We have received the header, so we know this destination socket -+ * address is working, so initialize all remaining requests. */ -+ if (!requests_initialized) { -+ for (i = 1; i < concurrency; i++) { -+ con[i].socknum = i; -+ start_connect(&con[i]); -+ } -+ requests_initialized = 1; -+ } - } - } - else { -@@ -1734,11 +1764,10 @@ static void test(void) - apr_signal(SIGINT, output_results); - #endif - -- /* initialise lots of requests */ -- for (i = 0; i < concurrency; i++) { -- con[i].socknum = i; -- start_connect(&con[i]); -- } -+ /* initialise first connection to determine destination socket address -+ * which should be used for next connections. */ -+ con[0].socknum = 0; -+ start_connect(&con[0]); - - do { - apr_int32_t n; -@@ -1786,14 +1815,20 @@ static void test(void) - if ((rtnev & APR_POLLIN) || (rtnev & APR_POLLPRI) || (rtnev & APR_POLLHUP)) - read_connection(c); - if ((rtnev & APR_POLLERR) || (rtnev & APR_POLLNVAL)) { -- bad++; -- err_except++; -- /* avoid apr_poll/EINPROGRESS loop on HP-UX, let recv discover ECONNREFUSED */ -- if (c->state == STATE_CONNECTING) { -- read_connection(c); -+ if (destsa->next && c->state == STATE_CONNECTING && good == 0) { -+ destsa = destsa->next; -+ start_connect(c); - } - else { -- start_connect(c); -+ bad++; -+ err_except++; -+ /* avoid apr_poll/EINPROGRESS loop on HP-UX, let recv discover ECONNREFUSED */ -+ if (c->state == STATE_CONNECTING) { -+ read_connection(c); -+ } -+ else { -+ start_connect(c); -+ } - } - continue; - } diff --git a/SOURCES/httpd-2.4.6-r1332643+.patch b/SOURCES/httpd-2.4.6-r1332643+.patch deleted file mode 100644 index 69c451d..0000000 --- a/SOURCES/httpd-2.4.6-r1332643+.patch +++ /dev/null @@ -1,380 +0,0 @@ -diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c -index 987b256..c24c6e1 100644 ---- a/modules/ssl/mod_ssl.c -+++ b/modules/ssl/mod_ssl.c -@@ -514,6 +514,13 @@ int ssl_engine_disable(conn_rec *c) - return 1; - } - -+static int modssl_register_npn(conn_rec *c, -+ ssl_npn_advertise_protos advertisefn, -+ ssl_npn_proto_negotiated negotiatedfn) -+{ -+ return DECLINED; -+} -+ - int ssl_init_ssl_connection(conn_rec *c, request_rec *r) - { - SSLSrvConfigRec *sc; -@@ -706,6 +713,7 @@ static void ssl_register_hooks(apr_pool_t *p) - - APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable); - APR_REGISTER_OPTIONAL_FN(ssl_engine_disable); -+ APR_REGISTER_OPTIONAL_FN(modssl_register_npn); - - ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "ssl", - AUTHZ_PROVIDER_VERSION, -diff --git a/modules/ssl/mod_ssl.h b/modules/ssl/mod_ssl.h -index db8ffaf..d381901 100644 ---- a/modules/ssl/mod_ssl.h -+++ b/modules/ssl/mod_ssl.h -@@ -84,5 +84,40 @@ APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *)); - - APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *)); - -+/** The npn_advertise_protos callback allows another modules to add -+ * entries to the list of protocol names advertised by the server -+ * during the Next Protocol Negotiation (NPN) portion of the SSL -+ * handshake. The callback is given the connection and an APR array; -+ * it should push one or more char*'s pointing to NUL-terminated -+ * strings (such as "http/1.1" or "spdy/2") onto the array and return -+ * OK. To prevent further processing of (other modules') callbacks, -+ * return DONE. */ -+typedef int (*ssl_npn_advertise_protos)(conn_rec *connection, -+ apr_array_header_t *protos); -+ -+/** The npn_proto_negotiated callback allows other modules to discover -+ * the name of the protocol that was chosen during the Next Protocol -+ * Negotiation (NPN) portion of the SSL handshake. Note that this may -+ * be the empty string (in which case modules should probably assume -+ * HTTP), or it may be a protocol that was never even advertised by -+ * the server. The callback is given the connection, a -+ * non-NUL-terminated string containing the protocol name, and the -+ * length of the string; it should do something appropriate -+ * (i.e. insert or remove filters) and return OK. To prevent further -+ * processing of (other modules') callbacks, return DONE. */ -+typedef int (*ssl_npn_proto_negotiated)(conn_rec *connection, -+ const char *proto_name, -+ apr_size_t proto_name_len); -+ -+/* An optional function which can be used to register a pair of -+ * callbacks for NPN handling. This optional function should be -+ * invoked from a pre_connection hook which runs *after* mod_ssl.c's -+ * pre_connection hook. The function returns OK if the callbacks are -+ * register, or DECLINED otherwise (for example if mod_ssl does not -+l * support NPN). */ -+APR_DECLARE_OPTIONAL_FN(int, modssl_register_npn, (conn_rec *conn, -+ ssl_npn_advertise_protos advertisefn, -+ ssl_npn_proto_negotiated negotiatedfn)); -+ - #endif /* __MOD_SSL_H__ */ - /** @} */ -diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c -index 9526f1b..12b2115 100644 ---- a/modules/ssl/ssl_engine_init.c -+++ b/modules/ssl/ssl_engine_init.c -@@ -736,6 +736,11 @@ static void ssl_init_ctx_callbacks(server_rec *s, - #ifdef HAVE_TLS_ALPN - SSL_CTX_set_alpn_select_cb(ctx, ssl_callback_alpn_select, NULL); - #endif -+ -+#ifdef HAVE_TLS_NPN -+ SSL_CTX_set_next_protos_advertised_cb( -+ ctx, ssl_callback_AdvertiseNextProtos, NULL); -+#endif - } - - static apr_status_t ssl_init_ctx_verify(server_rec *s, -diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c -index d1f44e9..26ee301 100644 ---- a/modules/ssl/ssl_engine_io.c -+++ b/modules/ssl/ssl_engine_io.c -@@ -317,6 +317,7 @@ typedef struct { - apr_pool_t *pool; - char buffer[AP_IOBUFSIZE]; - ssl_filter_ctx_t *filter_ctx; -+ int npn_finished; /* 1 if NPN has finished, 0 otherwise */ - } bio_filter_in_ctx_t; - - /* -@@ -1517,6 +1518,38 @@ static apr_status_t ssl_io_filter_input(ap_filter_t *f, - return ssl_io_filter_error(inctx, bb, status, is_init); - } - -+#ifdef HAVE_TLS_NPN -+ /* By this point, Next Protocol Negotiation (NPN) should be completed (if -+ * our version of OpenSSL supports it). If we haven't already, find out -+ * which protocol was decided upon and inform other modules by calling -+ * npn_proto_negotiated_hook. */ -+ if (!inctx->npn_finished) { -+ SSLConnRec *sslconn = myConnConfig(f->c); -+ apr_array_header_t *protos = apr_array_make(f->c->pool, 1, sizeof(char *)); -+ const unsigned char *next_proto = NULL; -+ unsigned next_proto_len = 0; -+ const unsigned char *out; -+ unsigned char outlen; -+ -+ SSL_get0_next_proto_negotiated(inctx->ssl, &next_proto, &next_proto_len); -+ if (next_proto_len) { -+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c, -+ APLOGNO(02306) "SSL NPN negotiated protocol: '%.*s'", -+ next_proto_len, (const char*)next_proto); -+ -+ APR_ARRAY_PUSH(protos, char *) = -+ apr_pstrmemdup(f->c->pool, (const char *)next_proto, next_proto_len); -+ -+ if (modssl_select_protocol(inctx->ssl, f->c, sslconn, protos, -+ &out, &outlen) != SSL_TLSEXT_ERR_OK) -+ ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c, -+ "SSL NPN negotiation failed"); -+ } -+ -+ inctx->npn_finished = 1; -+ } -+#endif -+ - if (is_init) { - /* protocol module needs to handshake before sending - * data to client (e.g. NNTP or FTP) -@@ -2041,6 +2074,7 @@ static void ssl_io_input_add_filter(ssl_filter_ctx_t *filter_ctx, conn_rec *c, - inctx->block = APR_BLOCK_READ; - inctx->pool = c->pool; - inctx->filter_ctx = filter_ctx; -+ inctx->npn_finished = 0; - } - - /* The request_rec pointer is passed in here only to ensure that the -diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c -index 02acd22..dced334 100644 ---- a/modules/ssl/ssl_engine_kernel.c -+++ b/modules/ssl/ssl_engine_kernel.c -@@ -2332,6 +2332,142 @@ int ssl_callback_SessionTicket(SSL *ssl, - } - #endif /* HAVE_TLS_SESSION_TICKETS */ - -+#if defined(HAVE_TLS_NPN) || defined(HAVE_TLS_ALPN) -+int modssl_select_protocol(SSL *ssl, conn_rec *c, SSLConnRec *sslconn, -+ apr_array_header_t *client_protos, -+ const unsigned char **out, unsigned char *outlen) -+{ -+ const char *proposed; -+ size_t len; -+ -+ /* The order the callbacks are invoked from TLS extensions is, unfortunately -+ * not defined and older openssl versions do call ALPN selection before -+ * they callback the SNI. We need to make sure that we know which vhost -+ * we are dealing with so we respect the correct protocols. -+ */ -+ init_vhost(c, ssl); -+ -+ proposed = ap_select_protocol(c, NULL, sslconn->server, client_protos); -+ if (!proposed) { -+ proposed = ap_get_protocol(c); -+ } -+ -+ len = strlen(proposed); -+ if (len > 255) { -+ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02840) -+ "ALPN negotiated protocol name too long"); -+ return SSL_TLSEXT_ERR_ALERT_FATAL; -+ } -+ *out = (const unsigned char *)proposed; -+ *outlen = (unsigned char)len; -+ -+ ap_log_cerror(APLOG_MARK, APLOG_TRACE8, 0, c, -+ "protocol switching from '%s' to '%s'", -+ ap_get_protocol(c), proposed); -+ -+ if (strcmp(proposed, ap_get_protocol(c))) { -+ apr_status_t status; -+ -+ status = ap_switch_protocol(c, NULL, sslconn->server, proposed); -+ if (status != APR_SUCCESS) { -+ ap_log_cerror(APLOG_MARK, APLOG_ERR, status, c, -+ APLOGNO(02908) "protocol switch to '%s' failed", -+ proposed); -+ return SSL_TLSEXT_ERR_ALERT_FATAL; -+ } -+ } -+ -+ return SSL_TLSEXT_ERR_OK; -+} -+#endif /* defined(HAVE_TLS_NPN) || defined(HAVE_TLS_ALPN) */ -+ -+#ifdef HAVE_TLS_NPN -+/* -+ * This callback function is executed when SSL needs to decide what protocols -+ * to advertise during Next Protocol Negotiation (NPN). It must produce a -+ * string in wire format -- a sequence of length-prefixed strings -- indicating -+ * the advertised protocols. Refer to SSL_CTX_set_next_protos_advertised_cb -+ * in OpenSSL for reference. -+ */ -+int ssl_callback_AdvertiseNextProtos(SSL *ssl, const unsigned char **data_out, -+ unsigned int *size_out, void *arg) -+{ -+ conn_rec *c = (conn_rec*)SSL_get_app_data(ssl); -+ SSLConnRec *sslconn = myConnConfig(c); -+ const apr_array_header_t *protos; -+ int num_protos; -+ unsigned int size; -+ int i; -+ unsigned char *data; -+ unsigned char *start; -+ -+ *data_out = NULL; -+ *size_out = 0; -+ -+ /* If the connection object is not available, or there are no -+ upgrades available, do nothing. */ -+ if (!c || ap_get_protocol_upgrades(c, NULL, sslconn->server, 0, &protos)) { -+ return SSL_TLSEXT_ERR_NOACK; -+ } -+ -+ num_protos = protos ? protos->nelts : 0; -+ -+ if (num_protos == 0) { -+ return SSL_TLSEXT_ERR_NOACK; -+ } -+ -+ /* We now have a list of null-terminated strings; we need to concatenate -+ * them together into a single string, where each protocol name is prefixed -+ * by its length. First, calculate how long that string will be. */ -+ size = 0; -+ for (i = 0; i < num_protos; ++i) { -+ const char *string = APR_ARRAY_IDX(protos, i, const char*); -+ unsigned int length = strlen(string); -+ /* If the protocol name is too long (the length must fit in one byte), -+ * then log an error and skip it. */ -+ if (length > 255) { -+ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02307) -+ "SSL NPN protocol name too long (length=%u): %s", -+ length, string); -+ continue; -+ } -+ /* Leave room for the length prefix (one byte) plus the protocol name -+ * itself. */ -+ size += 1 + length; -+ } -+ -+ /* If there is nothing to advertise (either because no modules added -+ * anything to the protos array, or because all strings added to the array -+ * were skipped), then we're done. */ -+ if (size == 0) { -+ return SSL_TLSEXT_ERR_OK; -+ } -+ -+ /* Now we can build the string. Copy each protocol name string into the -+ * larger string, prefixed by its length. */ -+ data = apr_palloc(c->pool, size * sizeof(unsigned char)); -+ start = data; -+ for (i = 0; i < num_protos; ++i) { -+ const char *string = APR_ARRAY_IDX(protos, i, const char*); -+ apr_size_t length = strlen(string); -+ if (length > 255) -+ continue; -+ *start = (unsigned char)length; -+ ++start; -+ memcpy(start, string, length * sizeof(unsigned char)); -+ start += length; -+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, -+ "SSL NPN protocol advertising: %s", string); -+ } -+ -+ /* Success. */ -+ *data_out = data; -+ *size_out = size; -+ return SSL_TLSEXT_ERR_OK; -+} -+ -+#endif /* HAVE_TLS_NPN */ -+ - #ifdef HAVE_TLS_ALPN - - /* -@@ -2354,8 +2490,6 @@ int ssl_callback_alpn_select(SSL *ssl, - conn_rec *c = (conn_rec*)SSL_get_app_data(ssl); - SSLConnRec *sslconn = myConnConfig(c); - apr_array_header_t *client_protos; -- const char *proposed; -- size_t len; - int i; - - /* If the connection object is not available, -@@ -2385,40 +2519,7 @@ int ssl_callback_alpn_select(SSL *ssl, - i += plen; - } - -- /* The order the callbacks are invoked from TLS extensions is, unfortunately -- * not defined and older openssl versions do call ALPN selection before -- * they callback the SNI. We need to make sure that we know which vhost -- * we are dealing with so we respect the correct protocols. -- */ -- init_vhost(c, ssl); -- -- proposed = ap_select_protocol(c, NULL, sslconn->server, client_protos); -- if (!proposed) { -- proposed = ap_get_protocol(c); -- } -- -- len = strlen(proposed); -- if (len > 255) { -- ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02840) -- "ALPN negotiated protocol name too long"); -- return SSL_TLSEXT_ERR_ALERT_FATAL; -- } -- *out = (const unsigned char *)proposed; -- *outlen = (unsigned char)len; -- -- if (strcmp(proposed, ap_get_protocol(c))) { -- apr_status_t status; -- -- status = ap_switch_protocol(c, NULL, sslconn->server, proposed); -- if (status != APR_SUCCESS) { -- ap_log_cerror(APLOG_MARK, APLOG_ERR, status, c, -- APLOGNO(02908) "protocol switch to '%s' failed", -- proposed); -- return SSL_TLSEXT_ERR_ALERT_FATAL; -- } -- } -- -- return SSL_TLSEXT_ERR_OK; -+ return modssl_select_protocol(ssl, c, sslconn, client_protos, out, outlen); - } - #endif /* HAVE_TLS_ALPN */ - -diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h -index 41b4387..7c440ef 100644 ---- a/modules/ssl/ssl_private.h -+++ b/modules/ssl/ssl_private.h -@@ -98,6 +98,8 @@ - #include - #include - -+#include "mod_ssl.h" -+ - /* Avoid tripping over an engine build installed globally and detected - * when the user points at an explicit non-engine flavor of OpenSSL - */ -@@ -127,6 +129,11 @@ - #define HAVE_FIPS - #endif - -+#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_NEXTPROTONEG) \ -+ && !defined(OPENSSL_NO_TLSEXT) -+#define HAVE_TLS_NPN -+#endif -+ - #if defined(SSL_OP_NO_TLSv1_2) - #define HAVE_TLSV1_X - #endif -@@ -872,6 +879,10 @@ int ssl_callback_ServerNameIndication(SSL *, int *, modssl_ctx_t *); - int ssl_callback_SessionTicket(SSL *, unsigned char *, unsigned char *, - EVP_CIPHER_CTX *, HMAC_CTX *, int); - #endif -+int ssl_callback_AdvertiseNextProtos(SSL *ssl, const unsigned char **data, unsigned int *len, void *arg); -+int modssl_select_protocol(SSL *ssl, conn_rec *c, SSLConnRec *sslconn, -+ apr_array_header_t *client_protos, -+ const unsigned char **out, unsigned char *outlen); - - #ifdef HAVE_TLS_ALPN - int ssl_callback_alpn_select(SSL *ssl, const unsigned char **out, diff --git a/SOURCES/httpd-2.4.6-r1556473.patch b/SOURCES/httpd-2.4.6-r1556473.patch deleted file mode 100644 index 009baa7..0000000 --- a/SOURCES/httpd-2.4.6-r1556473.patch +++ /dev/null @@ -1,31 +0,0 @@ -# ./pullrev.sh 1556473 - -https://bugzilla.redhat.com/show_bug.cgi?id=1036666 - -http://svn.apache.org/viewvc?view=revision&revision=1556473 - ---- httpd-2.4.6/modules/ssl/ssl_engine_config.c -+++ httpd-2.4.6/modules/ssl/ssl_engine_config.c -@@ -699,9 +699,20 @@ - #ifndef SSL_OP_NO_COMPRESSION - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err) -- return "This version of openssl does not support configuring " -- "compression within sections."; -+ return "This version of OpenSSL does not support enabling " -+ "SSLCompression within sections."; - #endif -+ if (flag) { -+ /* Some (packaged) versions of OpenSSL do not support -+ * compression by default. Enabling this directive would not -+ * have the desired effect, so fail with an error. */ -+ STACK_OF(SSL_COMP) *meths = SSL_COMP_get_compression_methods(); -+ -+ if (sk_SSL_COMP_num(meths) == 0) { -+ return "This version of OpenSSL does not have any compression methods " -+ "available, cannot enable SSLCompression."; -+ } -+ } - sc->compression = flag ? TRUE : FALSE; - return NULL; - #else diff --git a/SOURCES/httpd-2.4.6-r1664565.patch b/SOURCES/httpd-2.4.6-r1664565.patch deleted file mode 100644 index 7b5a703..0000000 --- a/SOURCES/httpd-2.4.6-r1664565.patch +++ /dev/null @@ -1,70 +0,0 @@ -diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c -index 3d1fe3c..b5c73f7 100644 ---- a/modules/mappers/mod_rewrite.c -+++ b/modules/mappers/mod_rewrite.c -@@ -265,6 +265,8 @@ typedef struct { - const char *dbdq; /* SQL SELECT statement for rewritemap */ - const char *checkfile2; /* filename to check for map existence - NULL if only one file */ -+ const char *user; /* run RewriteMap program as this user */ -+ const char *group; /* run RewriteMap program as this group */ - } rewritemap_entry; - - /* special pattern types for RewriteCond */ -@@ -1191,6 +1193,7 @@ static void rewrite_child_errfn(apr_pool_t *p, apr_status_t err, - - static apr_status_t rewritemap_program_child(apr_pool_t *p, - const char *progname, char **argv, -+ const char *user, const char *group, - apr_file_t **fpout, - apr_file_t **fpin) - { -@@ -1203,6 +1206,8 @@ static apr_status_t rewritemap_program_child(apr_pool_t *p, - APR_FULL_BLOCK, APR_NO_PIPE)) - && APR_SUCCESS == (rc=apr_procattr_dir_set(procattr, - ap_make_dirstr_parent(p, argv[0]))) -+ && (!user || APR_SUCCESS == (rc=apr_procattr_user_set(procattr, user, ""))) -+ && (!group || APR_SUCCESS == (rc=apr_procattr_group_set(procattr, group))) - && APR_SUCCESS == (rc=apr_procattr_cmdtype_set(procattr, APR_PROGRAM)) - && APR_SUCCESS == (rc=apr_procattr_child_errfn_set(procattr, - rewrite_child_errfn)) -@@ -1260,6 +1265,7 @@ static apr_status_t run_rewritemap_programs(server_rec *s, apr_pool_t *p) - } - - rc = rewritemap_program_child(p, map->argv[0], map->argv, -+ map->user, map->group, - &fpout, &fpin); - if (rc != APR_SUCCESS || fpin == NULL || fpout == NULL) { - ap_log_error(APLOG_MARK, APLOG_ERR, rc, s, APLOGNO(00654) -@@ -3048,7 +3054,7 @@ static const char *cmd_rewriteoptions(cmd_parms *cmd, - } - - static const char *cmd_rewritemap(cmd_parms *cmd, void *dconf, const char *a1, -- const char *a2) -+ const char *a2, const char *a3) - { - rewrite_server_conf *sconf; - rewritemap_entry *newmap; -@@ -3154,6 +3160,11 @@ static const char *cmd_rewritemap(cmd_parms *cmd, void *dconf, const char *a1, - - newmap->type = MAPTYPE_PRG; - newmap->checkfile = newmap->argv[0]; -+ if (a3) { -+ char *tok_cntx; -+ newmap->user = apr_strtok(apr_pstrdup(cmd->pool, a3), ":", &tok_cntx); -+ newmap->group = apr_strtok(NULL, ":", &tok_cntx); -+ } - } - else if (strncasecmp(a2, "int:", 4) == 0) { - newmap->type = MAPTYPE_INT; -@@ -5265,8 +5276,8 @@ static const command_rec command_table[] = { - "an input string and a to be applied regexp-pattern"), - AP_INIT_RAW_ARGS("RewriteRule", cmd_rewriterule, NULL, OR_FILEINFO, - "an URL-applied regexp-pattern and a substitution URL"), -- AP_INIT_TAKE2( "RewriteMap", cmd_rewritemap, NULL, RSRC_CONF, -- "a mapname and a filename"), -+ AP_INIT_TAKE23( "RewriteMap", cmd_rewritemap, NULL, RSRC_CONF, -+ "a mapname and a filename and options"), - { NULL } - }; - diff --git a/SOURCES/httpd-2.4.6-rotatelog-timezone.patch b/SOURCES/httpd-2.4.6-rotatelog-timezone.patch deleted file mode 100644 index b22202e..0000000 --- a/SOURCES/httpd-2.4.6-rotatelog-timezone.patch +++ /dev/null @@ -1,97 +0,0 @@ -diff --git a/support/rotatelogs.c b/support/rotatelogs.c -index c2373f56..14b0ec4 100644 ---- a/support/rotatelogs.c -+++ b/support/rotatelogs.c -@@ -151,14 +151,14 @@ static void usage(const char *argv0, const char *reason) - exit(1); - } - --/* -- * Get the unix time with timezone corrections -- * given in the config struct. -- */ --static int get_now(rotate_config_t *config) -+/* This function returns the current Unix time (time_t) plus any -+ * configured or derived local time offset. The offset applied is -+ * returned via *offset. */ -+static int get_now(rotate_config_t *config, apr_int32_t *offset) - { - apr_time_t tNow = apr_time_now(); -- int utc_offset = config->utc_offset; -+ int utc_offset; -+ - if (config->use_localtime) { - /* Check for our UTC offset before using it, since it might - * change if there's a switch between standard and daylight -@@ -168,6 +168,13 @@ static int get_now(rotate_config_t *config) - apr_time_exp_lt(<, tNow); - utc_offset = lt.tm_gmtoff; - } -+ else { -+ utc_offset = config->utc_offset; -+ } -+ -+ if (offset) -+ *offset = utc_offset; -+ - return (int)apr_time_sec(tNow) + utc_offset; - } - -@@ -231,13 +238,13 @@ static void checkRotate(rotate_config_t *config, rotate_status_t *status) - status->rotateReason = ROTATE_SIZE; - } - else if (config->tRotation) { -- if (get_now(config) >= status->tLogEnd) { -+ if (get_now(config, NULL) >= status->tLogEnd) { - status->rotateReason = ROTATE_TIME; - } - } - } - else if (config->tRotation) { -- if (get_now(config) >= status->tLogEnd) { -+ if (get_now(config, NULL) >= status->tLogEnd) { - status->rotateReason = ROTATE_TIME; - } - } -@@ -361,12 +368,16 @@ static void truncate_and_write_error(rotate_status_t *status) - static void doRotate(rotate_config_t *config, rotate_status_t *status) - { - -- int now = get_now(config); -+ apr_int32_t offset; -+ int now; - int tLogStart; - apr_status_t rv; - struct logfile newlog; - int thisLogNum = -1; - -+ /* Retrieve local-time-adjusted-Unix-time. */ -+ now = get_now(config, &offset); -+ - status->rotateReason = ROTATE_NONE; - - if (config->tRotation) { -@@ -392,7 +403,13 @@ static void doRotate(rotate_config_t *config, rotate_status_t *status) - apr_time_exp_t e; - apr_size_t rs; - -- apr_time_exp_gmt(&e, tNow); -+ /* Explode the local-time-adjusted-Unix-time into a struct tm, -+ * first *reversing* local-time-adjustment applied by -+ * get_now() if we are using localtime. */ -+ if (config->use_localtime) -+ apr_time_exp_lt(&e, tNow - apr_time_from_sec(offset)); -+ else -+ apr_time_exp_gmt(&e, tNow); - apr_strftime(newlog.name, &rs, sizeof(newlog.name), config->szLogRoot, &e); - } - else { -@@ -660,7 +677,7 @@ int main (int argc, const char * const argv[]) - nRead = sizeof(buf); - #if APR_FILES_AS_SOCKETS - if (config.create_empty && config.tRotation) { -- polltimeout = status.tLogEnd ? status.tLogEnd - get_now(&config) : config.tRotation; -+ polltimeout = status.tLogEnd ? status.tLogEnd - get_now(&config, NULL) : config.tRotation; - if (polltimeout <= 0) { - pollret = APR_TIMEUP; - } diff --git a/SOURCES/httpd-2.4.6-sigint.patch b/SOURCES/httpd-2.4.6-sigint.patch deleted file mode 100644 index ecdd82e..0000000 --- a/SOURCES/httpd-2.4.6-sigint.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff --git a/server/mpm/prefork/prefork.c b/server/mpm/prefork/prefork.c -index 559f90a..a386a75 100644 ---- a/server/mpm/prefork/prefork.c -+++ b/server/mpm/prefork/prefork.c -@@ -220,6 +220,9 @@ static void clean_child_exit(int code) - { - retained->mpm->mpm_state = AP_MPMQ_STOPPING; - -+ apr_signal(SIGHUP, SIG_IGN); -+ apr_signal(SIGTERM, SIG_IGN); -+ - if (pchild) { - apr_pool_destroy(pchild); - } -@@ -699,6 +702,13 @@ static int make_child(server_rec *s, int slot, int bucket) - */ - apr_signal(SIGHUP, just_die); - apr_signal(SIGTERM, just_die); -+ /* Ignore SIGINT in child. This fixes race-condition in signals -+ * handling when httpd is runnning on foreground and user hits ctrl+c. -+ * In this case, SIGINT is sent to all children followed by SIGTERM -+ * from the main process, which interrupts the SIGINT handler and -+ * leads to inconsistency. -+ */ -+ apr_signal(SIGINT, SIG_IGN); - /* The child process just closes listeners on AP_SIG_GRACEFUL. - * The pod is used for signalling the graceful restart. - */ diff --git a/SOURCES/httpd-2.4.6-sslmultiproxy.patch b/SOURCES/httpd-2.4.6-sslmultiproxy.patch deleted file mode 100644 index 02087ea..0000000 --- a/SOURCES/httpd-2.4.6-sslmultiproxy.patch +++ /dev/null @@ -1,100 +0,0 @@ -diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c -index 0d7c906..be2ee9f 100644 ---- a/modules/ssl/mod_ssl.c -+++ b/modules/ssl/mod_ssl.c -@@ -395,6 +395,9 @@ static SSLConnRec *ssl_init_connection_ctx(conn_rec *c) - return sslconn; - } - -+static typeof(ssl_proxy_enable) *othermod_proxy_enable; -+static typeof(ssl_engine_disable) *othermod_engine_disable; -+ - int ssl_proxy_enable(conn_rec *c) - { - SSLSrvConfigRec *sc; -@@ -403,6 +406,12 @@ int ssl_proxy_enable(conn_rec *c) - sc = mySrvConfig(sslconn->server); - - if (!sc->proxy_enabled) { -+ if (othermod_proxy_enable) { -+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, -+ "mod_ssl proxy not configured, passing through to other module."); -+ return othermod_proxy_enable(c); -+ } -+ - ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01961) - "SSL Proxy requested for %s but not enabled " - "[Hint: SSLProxyEngine]", sc->vhost_id); -@@ -422,6 +431,10 @@ int ssl_engine_disable(conn_rec *c) - - SSLConnRec *sslconn = myConnConfig(c); - -+ if (othermod_engine_disable) { -+ othermod_engine_disable(c); -+ } -+ - if (sslconn) { - sc = mySrvConfig(sslconn->server); - } -@@ -652,6 +665,9 @@ static void ssl_register_hooks(apr_pool_t *p) - ap_hook_post_read_request(ssl_hook_ReadReq, pre_prr,NULL, APR_HOOK_MIDDLE); - - ssl_var_register(p); -+ -+ othermod_proxy_enable = APR_RETRIEVE_OPTIONAL_FN(ssl_proxy_enable); -+ othermod_engine_disable = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable); - - APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable); - APR_REGISTER_OPTIONAL_FN(ssl_engine_disable); -diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c -index a6b0d0d..5a415b9 100644 ---- a/modules/ssl/ssl_engine_vars.c -+++ b/modules/ssl/ssl_engine_vars.c -@@ -55,6 +55,10 @@ static void ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algk - static char *ssl_var_lookup_ssl_version(apr_pool_t *p, char *var); - static char *ssl_var_lookup_ssl_compress_meth(SSL *ssl); - -+static APR_OPTIONAL_FN_TYPE(ssl_is_https) *othermod_is_https; -+static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *othermod_var_lookup; -+ -+ - static SSLConnRec *ssl_get_effective_config(conn_rec *c) - { - SSLConnRec *sslconn = myConnConfig(c); -@@ -68,7 +72,9 @@ static SSLConnRec *ssl_get_effective_config(conn_rec *c) - static int ssl_is_https(conn_rec *c) - { - SSLConnRec *sslconn = ssl_get_effective_config(c); -- return sslconn && sslconn->ssl; -+ -+ return (sslconn && sslconn->ssl) -+ || (othermod_is_https && othermod_is_https(c)); - } - - static const char var_interface[] = "mod_ssl/" AP_SERVER_BASEREVISION; -@@ -137,6 +143,9 @@ void ssl_var_register(apr_pool_t *p) - { - char *cp, *cp2; - -+ othermod_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https); -+ othermod_var_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup); -+ - APR_REGISTER_OPTIONAL_FN(ssl_is_https); - APR_REGISTER_OPTIONAL_FN(ssl_var_lookup); - APR_REGISTER_OPTIONAL_FN(ssl_ext_list); -@@ -272,6 +281,15 @@ char *ssl_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, - */ - if (result == NULL && c != NULL) { - SSLConnRec *sslconn = ssl_get_effective_config(c); -+ -+ if (strlen(var) > 4 && strcEQn(var, "SSL_", 4) -+ && (!sslconn || !sslconn->ssl) && othermod_var_lookup) { -+ /* For an SSL_* variable, if mod_ssl is not enabled for -+ * this connection and another SSL module is present, pass -+ * through to that module. */ -+ return othermod_var_lookup(p, s, c, r, var); -+ } -+ - if (strlen(var) > 4 && strcEQn(var, "SSL_", 4) - && sslconn && sslconn->ssl) - result = ssl_var_lookup_ssl(p, sslconn, r, var+4); diff --git a/SPECS/httpd.spec b/SPECS/httpd.spec index 1482119..dd85ff6 100644 --- a/SPECS/httpd.spec +++ b/SPECS/httpd.spec @@ -3,9 +3,11 @@ %if 0%{?rhel} >= 7 %define use_systemd 1 %define use_system_apr 1 +%define enable_mod_md 1 %else %define use_systemd 0 %define use_system_apr 0 +%define enable_mod_md 0 %endif # If we are using system APR and building as collection, we have to set @@ -48,8 +50,8 @@ Summary: Apache HTTP Server Name: %{?scl:%scl_prefix}httpd -Version: 2.4.27 -Release: 8%{?dist}.1 +Version: 2.4.34 +Release: 7%{?dist} URL: http://httpd.apache.org/ Source0: http://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2 Source1: index.html @@ -79,50 +81,47 @@ Source26: action-graceful.sh Source27: action-configtest.sh Source28: 00-optional.conf Source29: httpd-scl-wrapper +Source30: 01-md.conf + # Documentation -Source30: README.confd Source40: htcacheclean.service Source41: htcacheclean.sysconf Source42: htcacheclean.init +Source43: README.confd + # build/scripts patches Patch1: httpd-2.4.1-apctl.patch Patch2: httpd-2.4.25-apxs.patch Patch3: httpd-2.4.1-deplibs.patch Patch5: httpd-2.4.3-layout.patch Patch6: httpd-2.4.3-apctl-systemd.patch -Patch7: httpd-2.4.12-skiplist.patch +Patch7: httpd-2.4.34-skiplist.patch Patch8: httpd-2.4.25-detect-systemd.patch # Features/functional changes Patch20: httpd-2.4.10-mod_systemd.patch Patch21: httpd-2.4.6-full-release.patch -Patch23: httpd-2.4.4-export.patch +Patch23: httpd-2.4.34-export.patch Patch24: httpd-2.4.1-corelimit.patch Patch25: httpd-2.4.25-selinux.patch -Patch26: httpd-2.4.4-r1337344+.patch Patch27: httpd-2.4.2-icons.patch -Patch28: httpd-2.4.6-r1332643+.patch Patch30: httpd-2.4.4-cachehardmax.patch -Patch31: httpd-2.4.6-sslmultiproxy.patch -Patch32: httpd-2.4.3-sslsninotreq.patch -Patch33: httpd-2.4.26-sslalpnthunks.patch # Bug fixes -Patch56: httpd-2.4.4-mod_unique_id.patch -Patch59: httpd-2.4.6-r1556473.patch Patch62: httpd-2.4.6-apachectl-status.patch -Patch63: httpd-2.4.6-ab-overflow.patch -Patch64: httpd-2.4.6-sigint.patch Patch65: httpd-2.4.17-autoindex-revert.patch -Patch68: httpd-2.4.6-ap-ipv6.patch Patch69: httpd-2.4.6-apachectl-httpd-env.patch Patch70: httpd-2.4.6-bomb.patch Patch71: httpd-2.4.18-apachectl-httpd-env2.patch Patch74: httpd-2.4.25-rev-r1748324+.patch -Patch75: httpd-2.4.6-r1664565.patch -Patch76: httpd-2.4.6-rotatelog-timezone.patch -Patch77: httpd-2.4.27-mod_authz_dbd-missing-query.patch -Patch78: httpd-2.4.27-r1807771.patch +Patch75: httpd-2.4.34-apr-escape.patch +Patch76: httpd-2.4.34-scl-libnghttp2.patch +Patch77: httpd-2.4.34-scl-libcurl.patch +Patch78: httpd-2.4.33-mddefault.patch +Patch79: httpd-2.4.34-r1836472.patch +Patch80: httpd-2.4.34-statements-comment.patch + # Security fixes -Patch200: httpd-2.4.27-CVE-2017-9798.patch +Patch200: httpd-2.4.34-CVE-2018-11763.patch + License: ASL 2.0 Group: System Environment/Daemons BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root @@ -224,6 +223,21 @@ The mod_ssl module provides strong cryptography for the Apache Web server via the Secure Sockets Layer (SSL) and Transport Layer Security (TLS) protocols. +%if %{enable_mod_md} +%package -n %{?scl:%scl_prefix}mod_md +Group: System Environment/Daemons +Summary: Certificate provisioning using ACME for the Apache HTTP Server +Requires: %{?scl:%scl_prefix}httpd = 0:%{version}-%{release}, %{?scl:%scl_prefix}httpd-mmn = %{mmnisa} +BuildRequires: jansson-devel, %{?scl:%scl_prefix}libcurl-devel + +%description -n %{?scl:%scl_prefix}mod_md +This module manages common properties of domains for one or more +virtual hosts. Specifically it can use the ACME protocol (RFC Draft) +to automate certificate provisioning. These will be configured for +managed domains and their virtual hosts automatically. This includes +renewal of certificates before they expire. +%endif + %package -n %{?scl:%scl_prefix}mod_proxy_html Group: System Environment/Daemons Summary: HTML and XML content filters for the Apache HTTP Server @@ -261,6 +275,11 @@ authentication to the Apache HTTP Server. Group: System Environment/Daemons Summary: Session interface for the Apache HTTP Server Requires: %{?scl:%scl_prefix}httpd = 0:%{version}-%{release}, %{?scl:%scl_prefix}httpd-mmn = %{mmnisa} +%if %{use_system_apr} +Requires: apr-util-openssl +%else +Requires: %{?scl:%scl_prefix}apr-util-openssl +%endif %if 0%{?rhel} < 7 Requires(post): policycoreutils Requires(post): policycoreutils-python @@ -275,6 +294,7 @@ interface for storing and accessing per-user session data. export LD_LIBRARY_PATH=%{_libdir}:$LD_LIBRARY_PATH %endif %setup -q %{?scl:-n %{pkg_name}-%{version}} + %patch1 -p1 -b .apctl %patch2 -p1 -b .apxs %patch3 -p1 -b .deplibs @@ -293,29 +313,21 @@ export LD_LIBRARY_PATH=%{_libdir}:$LD_LIBRARY_PATH %patch23 -p1 -b .export %patch24 -p1 -b .corelimit %patch25 -p1 -b .selinux -%patch26 -p1 -b .r1337344+ %patch27 -p1 -b .icons -%patch28 -p1 -b .r1332643+ %patch30 -p1 -b .cachehardmax -%patch31 -p1 -b .sslmultiproxy -%patch32 -p1 -b .sslsninotreq -%patch33 -p1 -b .sslalpnthunks - -%patch56 -p1 -b .uniqueid -%patch59 -p1 -b .r1556473 -%patch63 -p1 -b .aboverflow -%patch64 -p1 -b .sigint + %patch65 -p1 -b .autoindexrevert -%patch68 -p1 -b .ipv6 %patch69 -p1 -b .envhttpd %patch70 -p1 -b .bomb %patch74 -p1 -b .rev-r1748324+ -%patch75 -p1 -b .r1664565 -%patch76 -p1 -b .rotatelogtimezone -%patch77 -p1 -b .missingquery -%patch78 -p1 -b .r1807771 +%patch75 -p1 -b .apr_escape +%patch76 -p1 -b .scl_libnghttp2 +%patch77 -p1 -b .scl_libcurl +%patch78 -p1 -b .md_default +%patch79 -p1 -b .r1836472 +%patch80 -p1 -b .statementscomment -%patch200 -p1 -b .CVE-2017-9798 +%patch200 -p1 -b .CVE-2018-11763 # Patch in the vendor string and the release string sed -i '/^#define PLATFORM/s/Unix/%{vstring}/' os/unix/os.h @@ -471,6 +483,9 @@ for f in 00-base.conf 00-mpm.conf 00-lua.conf 01-cgi.conf 00-dav.conf \ %if %{use_systemd} 00-systemd.conf \ %endif +%if %{enable_mod_md} + 01-md.conf \ +%endif 01-ldap.conf 01-session.conf 00-optional.conf; do install -m 644 -p $RPM_SOURCE_DIR/$f \ $RPM_BUILD_ROOT%{_sysconfdir}/httpd/conf.modules.d/$f @@ -531,6 +546,7 @@ sed -i 's|\$localstatedir|%{_localstatedir}|' \ # Other directories mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/lib/dav \ + $RPM_BUILD_ROOT%{_localstatedir}/lib/httpd \ $RPM_BUILD_ROOT%{_localstatedir}/run/httpd/htcacheclean # Create cache directory @@ -595,6 +611,7 @@ ln -s /usr/share/pixmaps/poweredby.png \ # symlinks for /etc/httpd ln -s %{httpd_logdir} $RPM_BUILD_ROOT/%{_sysconfdir}/httpd/logs +ln -s %{_localstatedir}/lib/httpd $RPM_BUILD_ROOT/%{_sysconfdir}/httpd/state ln -s %{_localstatedir}/run/httpd $RPM_BUILD_ROOT/%{_sysconfdir}/httpd/run ln -s %{_libdir}/httpd/modules $RPM_BUILD_ROOT/%{_sysconfdir}/httpd/modules @@ -822,6 +839,7 @@ rm -rf $RPM_BUILD_ROOT %dir %{_sysconfdir}/httpd %{_sysconfdir}/httpd/modules %{_sysconfdir}/httpd/logs +%{_sysconfdir}/httpd/state %{_sysconfdir}/httpd/run %dir %{_sysconfdir}/httpd/conf %config(noreplace) %{_sysconfdir}/httpd/conf/httpd.conf @@ -841,6 +859,9 @@ rm -rf $RPM_BUILD_ROOT %exclude %{_sysconfdir}/httpd/conf.modules.d/00-proxyhtml.conf %exclude %{_sysconfdir}/httpd/conf.modules.d/01-ldap.conf %exclude %{_sysconfdir}/httpd/conf.modules.d/01-session.conf +%if %{enable_mod_md} +%exclude %{_sysconfdir}/httpd/conf.modules.d/01-md.conf +%endif %config(noreplace) %{_sysconfdir}/sysconfig/httpd %config(noreplace) %{_sysconfdir}/sysconfig/htcacheclean @@ -898,6 +919,7 @@ rm -rf $RPM_BUILD_ROOT %attr(0700,apache,apache) %dir %{_localstatedir}/run/httpd/htcacheclean %attr(0700,root,root) %dir %{httpd_logdir} %attr(0700,apache,apache) %dir %{_localstatedir}/lib/dav +%attr(0700,apache,apache) %dir %{_localstatedir}/lib/httpd %attr(0700,apache,apache) %dir %{_localstatedir}/cache/httpd %attr(0700,apache,apache) %dir %{_localstatedir}/cache/httpd/proxy @@ -948,6 +970,12 @@ rm -rf $RPM_BUILD_ROOT %{_libdir}/httpd/modules/mod_auth_form.so %config(noreplace) %{_sysconfdir}/httpd/conf.modules.d/01-session.conf +%if %{enable_mod_md} +%files -n %{?scl:%scl_prefix}mod_md +%{_libdir}/httpd/modules/mod_md.so +%config(noreplace) %{_sysconfdir}/httpd/conf.modules.d/01-md.conf +%endif + %files devel %defattr(-,root,root) %{_includedir}/httpd @@ -963,8 +991,32 @@ rm -rf $RPM_BUILD_ROOT %endif %changelog -* Fri May 04 2018 Luboš Uhliarik - 2.4.27-8.1 -- Resolves: #1569093 - HTTP/2 connections hang and timeout +* Tue Nov 06 2018 Luboš Uhliarik - 2.4.34-7 +- Resolves: #1646937 - Unable to start httpd +- Resolves: #1638711 - comments should be allowed at the end of Allow from + statements + +* Wed Oct 31 2018 Luboš Uhliarik - 2.4.34-6 +- Resolves: #1644643 - httpd 2.4.34 regressions + +* Thu Oct 25 2018 Luboš Uhliarik - 2.4.34-5 +- Resolves: #1640722 - mod_md is missing in httpd24-httpd +- Resolves: #1635838 - CVE-2018-11763 httpd24-httpd: httpd: + DoS for HTTP/2 connections by continuous SETTINGS + +* Thu Sep 27 2018 Luboš Uhliarik - 2.4.34-3 +- Resolves: #1633260 - mod_session missing apr-util-openssl + +* Thu Sep 13 2018 Luboš Uhliarik - 2.4.34-2 +- Resolves: #1540167 - provides without httpd24 pre/in-fix + +* Thu Jul 19 2018 Luboš Uhliarik - 2.4.34-1 +- update to version 2.4.34 +- removed upstread Fedora layout +- load mod_proxy_uwsgi by default + +* Wed May 02 2018 Luboš Uhliarik - 2.4.27-9 +- Resolves: #1518737 - HTTP/2 connections hang and timeout * Wed Sep 20 2017 Luboš Uhliarik - 2.4.27-8 - Resolves: #1480506 - mod_authz_dbd segfaults when AuthzDBDQuery missing