From 3be11b9e0c68af20134f68ee62f6eb194f415262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Uhliarik?= Date: Wed, 2 Jun 2021 14:26:59 +0200 Subject: [PATCH 1/3] new version 2.4.48 Resolves: #1964746 - httpd-2.4.48 is available --- .gitignore | 1 + httpd-2.4.43-r1870095+.patch | 115 ----------- httpd-2.4.43-sslcoalesce.patch | 192 ------------------ httpd-2.4.46-lua-resume.patch | 119 ----------- ...-export.patch => httpd-2.4.48-export.patch | 6 +- ...929+.patch => httpd-2.4.48-r1842929+.patch | 27 +-- httpd.spec | 18 +- sources | 6 +- 8 files changed, 29 insertions(+), 455 deletions(-) delete mode 100644 httpd-2.4.43-r1870095+.patch delete mode 100644 httpd-2.4.43-sslcoalesce.patch delete mode 100644 httpd-2.4.46-lua-resume.patch rename httpd-2.4.43-export.patch => httpd-2.4.48-export.patch (93%) rename httpd-2.4.43-r1842929+.patch => httpd-2.4.48-r1842929+.patch (91%) diff --git a/.gitignore b/.gitignore index 09a5a07..ea4148c 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ x86_64 /httpd-2.4.43.tar.bz2.asc /KEYS /httpd-2.4.46.tar.bz2.asc +/httpd-2.4.48.tar.bz2.asc diff --git a/httpd-2.4.43-r1870095+.patch b/httpd-2.4.43-r1870095+.patch deleted file mode 100644 index 3fc8dfb..0000000 --- a/httpd-2.4.43-r1870095+.patch +++ /dev/null @@ -1,115 +0,0 @@ -diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c -index cbab6a3..765aa4b 100644 ---- a/modules/ssl/ssl_engine_kernel.c -+++ b/modules/ssl/ssl_engine_kernel.c -@@ -114,6 +114,45 @@ static int has_buffered_data(request_rec *r) - return result; - } - -+/* If a renegotiation is required for the location, and the request -+ * includes a message body (and the client has not requested a "100 -+ * Continue" response), then the client will be streaming the request -+ * body over the wire already. In that case, it is not possible to -+ * stop and perform a new SSL handshake immediately; once the SSL -+ * library moves to the "accept" state, it will reject the SSL packets -+ * which the client is sending for the request body. -+ * -+ * To allow authentication to complete in the hook, the solution used -+ * here is to fill a (bounded) buffer with the request body, and then -+ * to reinject that request body later. -+ * -+ * This function is called to fill the renegotiation buffer for the -+ * location as required, or fail. Returns zero on success or HTTP_ -+ * error code on failure. -+ */ -+static int fill_reneg_buffer(request_rec *r, SSLDirConfigRec *dc) -+{ -+ int rv; -+ apr_size_t rsize; -+ -+ /* ### this is HTTP/1.1 specific, special case for protocol? */ -+ if (r->expecting_100 || !ap_request_has_body(r)) { -+ return 0; -+ } -+ -+ rsize = dc->nRenegBufferSize == UNSET ? DEFAULT_RENEG_BUFFER_SIZE : dc->nRenegBufferSize; -+ if (rsize > 0) { -+ /* Fill the I/O buffer with the request body if possible. */ -+ rv = ssl_io_buffer_fill(r, rsize); -+ } -+ else { -+ /* If the reneg buffer size is set to zero, just fail. */ -+ rv = HTTP_REQUEST_ENTITY_TOO_LARGE; -+ } -+ -+ return rv; -+} -+ - #ifdef HAVE_TLSEXT - static int ap_array_same_str_set(apr_array_header_t *s1, apr_array_header_t *s2) - { -@@ -814,41 +853,14 @@ static int ssl_hook_Access_classic(request_rec *r, SSLSrvConfigRec *sc, SSLDirCo - } - } - -- /* If a renegotiation is now required for this location, and the -- * request includes a message body (and the client has not -- * requested a "100 Continue" response), then the client will be -- * streaming the request body over the wire already. In that -- * case, it is not possible to stop and perform a new SSL -- * handshake immediately; once the SSL library moves to the -- * "accept" state, it will reject the SSL packets which the client -- * is sending for the request body. -- * -- * To allow authentication to complete in this auth hook, the -- * solution used here is to fill a (bounded) buffer with the -- * request body, and then to reinject that request body later. -- */ -- if (renegotiate && !renegotiate_quick -- && !r->expecting_100 -- && ap_request_has_body(r)) { -- int rv; -- apr_size_t rsize; -- -- rsize = dc->nRenegBufferSize == UNSET ? DEFAULT_RENEG_BUFFER_SIZE : -- dc->nRenegBufferSize; -- if (rsize > 0) { -- /* Fill the I/O buffer with the request body if possible. */ -- rv = ssl_io_buffer_fill(r, rsize); -- } -- else { -- /* If the reneg buffer size is set to zero, just fail. */ -- rv = HTTP_REQUEST_ENTITY_TOO_LARGE; -- } -- -- if (rv) { -+ /* Fill reneg buffer if required. */ -+ if (renegotiate && !renegotiate_quick) { -+ rc = fill_reneg_buffer(r, dc); -+ if (rc) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02257) - "could not buffer message body to allow " - "SSL renegotiation to proceed"); -- return rv; -+ return rc; - } - } - -@@ -1132,6 +1144,17 @@ static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirCon - } - } - -+ /* Fill reneg buffer if required. */ -+ if (change_vmode) { -+ rc = fill_reneg_buffer(r, dc); -+ if (rc) { -+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10228) -+ "could not buffer message body to allow " -+ "TLS Post-Handshake Authentication to proceed"); -+ return rc; -+ } -+ } -+ - if (change_vmode) { - char peekbuf[1]; - diff --git a/httpd-2.4.43-sslcoalesce.patch b/httpd-2.4.43-sslcoalesce.patch deleted file mode 100644 index ef1f728..0000000 --- a/httpd-2.4.43-sslcoalesce.patch +++ /dev/null @@ -1,192 +0,0 @@ - -http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_engine_io.c?r1=1836237&r2=1836236&pathrev=1836237&view=patch -http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_engine_io.c?r1=1873985&r2=1876037&view=patch - ---- httpd-2.4.43/modules/ssl/ssl_engine_io.c.sslcoalesce -+++ httpd-2.4.43/modules/ssl/ssl_engine_io.c -@@ -1585,18 +1585,32 @@ - } - - --/* ssl_io_filter_output() produces one SSL/TLS message per bucket -+/* ssl_io_filter_output() produces one SSL/TLS record per bucket - * passed down the output filter stack. This results in a high -- * overhead (network packets) for any output comprising many small -- * buckets. SSI page applied through the HTTP chunk filter, for -- * example, may produce many brigades containing small buckets - -- * [chunk-size CRLF] [chunk-data] [CRLF]. -+ * overhead (more network packets & TLS processing) for any output -+ * comprising many small buckets. SSI output passed through the HTTP -+ * chunk filter, for example, may produce many brigades containing -+ * small buckets - [chunk-size CRLF] [chunk-data] [CRLF]. - * -- * The coalescing filter merges many small buckets into larger buckets -- * where possible, allowing the SSL I/O output filter to handle them -- * more efficiently. */ -+ * Sending HTTP response headers as a separate TLS record to the -+ * response body also reveals information to a network observer (the -+ * size of headers) which can be significant. -+ * -+ * The coalescing filter merges data buckets with the aim of producing -+ * fewer, larger TLS records - without copying/buffering all content -+ * and introducing unnecessary overhead. -+ * -+ * ### This buffering could be probably be done more comprehensively -+ * ### in ssl_io_filter_output itself. -+ * -+ * ### Another possible performance optimisation in particular for the -+ * ### [HEAP] [FILE] HTTP response case is using a brigade rather than -+ * ### a char array to buffer; using apr_brigade_write() to append -+ * ### will use already-allocated memory from the HEAP, reducing # of -+ * ### copies. -+ */ - --#define COALESCE_BYTES (2048) -+#define COALESCE_BYTES (AP_IOBUFSIZE) - - struct coalesce_ctx { - char buffer[COALESCE_BYTES]; -@@ -1609,11 +1623,12 @@ - apr_bucket *e, *upto; - apr_size_t bytes = 0; - struct coalesce_ctx *ctx = f->ctx; -+ apr_size_t buffered = ctx ? ctx->bytes : 0; /* space used on entry */ - unsigned count = 0; - - /* The brigade consists of zero-or-more small data buckets which -- * can be coalesced (the prefix), followed by the remainder of the -- * brigade. -+ * can be coalesced (referred to as the "prefix"), followed by the -+ * remainder of the brigade. - * - * Find the last bucket - if any - of that prefix. count gives - * the number of buckets in the prefix. The "prefix" must contain -@@ -1628,24 +1643,97 @@ - e != APR_BRIGADE_SENTINEL(bb) - && !APR_BUCKET_IS_METADATA(e) - && e->length != (apr_size_t)-1 -- && e->length < COALESCE_BYTES -- && (bytes + e->length) < COALESCE_BYTES -- && (ctx == NULL -- || bytes + ctx->bytes + e->length < COALESCE_BYTES); -+ && e->length <= COALESCE_BYTES -+ && (buffered + bytes + e->length) <= COALESCE_BYTES; - e = APR_BUCKET_NEXT(e)) { -- if (e->length) count++; /* don't count zero-length buckets */ -- bytes += e->length; -+ /* don't count zero-length buckets */ -+ if (e->length) { -+ bytes += e->length; -+ count++; -+ } - } -+ -+ /* If there is room remaining and the next bucket is a data -+ * bucket, try to include it in the prefix to coalesce. For a -+ * typical [HEAP] [FILE] HTTP response brigade, this handles -+ * merging the headers and the start of the body into a single TLS -+ * record. */ -+ if (bytes + buffered > 0 -+ && bytes + buffered < COALESCE_BYTES -+ && e != APR_BRIGADE_SENTINEL(bb) -+ && !APR_BUCKET_IS_METADATA(e)) { -+ apr_status_t rv = APR_SUCCESS; -+ -+ /* For an indeterminate length bucket (PIPE/CGI/...), try a -+ * non-blocking read to have it morph into a HEAP. If the -+ * read fails with EAGAIN, it is harmless to try a split -+ * anyway, split is ENOTIMPL for most PIPE-like buckets. */ -+ if (e->length == (apr_size_t)-1) { -+ const char *discard; -+ apr_size_t ignore; -+ -+ rv = apr_bucket_read(e, &discard, &ignore, APR_NONBLOCK_READ); -+ if (rv != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(rv)) { -+ ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, f->c, APLOGNO(10232) -+ "coalesce failed to read from %s bucket", -+ e->type->name); -+ return AP_FILTER_ERROR; -+ } -+ } -+ -+ if (rv == APR_SUCCESS) { -+ /* If the read above made the bucket morph, it may now fit -+ * entirely within the buffer. Otherwise, split it so it does -+ * fit. */ -+ if (e->length > COALESCE_BYTES -+ || e->length + buffered + bytes > COALESCE_BYTES) { -+ rv = apr_bucket_split(e, COALESCE_BYTES - (buffered + bytes)); -+ } -+ -+ if (rv == APR_SUCCESS && e->length == 0) { -+ /* As above, don't count in the prefix if the bucket is -+ * now zero-length. */ -+ } -+ else if (rv == APR_SUCCESS) { -+ ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, f->c, -+ "coalesce: adding %" APR_SIZE_T_FMT " bytes " -+ "from split %s bucket, total %" APR_SIZE_T_FMT, -+ e->length, e->type->name, bytes + buffered); -+ -+ count++; -+ bytes += e->length; -+ e = APR_BUCKET_NEXT(e); -+ } -+ else if (rv != APR_ENOTIMPL) { -+ ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, f->c, APLOGNO(10233) -+ "coalesce: failed to split data bucket"); -+ return AP_FILTER_ERROR; -+ } -+ } -+ } -+ - upto = e; - -- /* Coalesce the prefix, if: -- * a) more than one bucket is found to coalesce, or -- * b) the brigade contains only a single data bucket, or -- * c) the data bucket is not last but we have buffered data already. -+ /* Coalesce the prefix, if any of the following are true: -+ * -+ * a) the prefix is more than one bucket -+ * OR -+ * b) the prefix is the entire brigade, which is a single bucket -+ * AND the prefix length is smaller than the buffer size, -+ * OR -+ * c) the prefix is a single bucket -+ * AND there is buffered data from a previous pass. -+ * -+ * The aim with (b) is to buffer a small bucket so it can be -+ * coalesced with future invocations of this filter. e.g. three -+ * calls each with a single 100 byte HEAP bucket should get -+ * coalesced together. But an invocation with a 8192 byte HEAP -+ * should pass through untouched. - */ - if (bytes > 0 - && (count > 1 -- || (upto == APR_BRIGADE_SENTINEL(bb)) -+ || (upto == APR_BRIGADE_SENTINEL(bb) -+ && bytes < COALESCE_BYTES) - || (ctx && ctx->bytes > 0))) { - /* If coalescing some bytes, ensure a context has been - * created. */ -@@ -1656,7 +1744,8 @@ - - ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, f->c, - "coalesce: have %" APR_SIZE_T_FMT " bytes, " -- "adding %" APR_SIZE_T_FMT " more", ctx->bytes, bytes); -+ "adding %" APR_SIZE_T_FMT " more (buckets=%u)", -+ ctx->bytes, bytes, count); - - /* Iterate through the prefix segment. For non-fatal errors - * in this loop it is safe to break out and fall back to the -@@ -1671,7 +1760,8 @@ - if (APR_BUCKET_IS_METADATA(e) - || e->length == (apr_size_t)-1) { - ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c, APLOGNO(02012) -- "unexpected bucket type during coalesce"); -+ "unexpected %s bucket during coalesce", -+ e->type->name); - break; /* non-fatal error; break out */ - } - diff --git a/httpd-2.4.46-lua-resume.patch b/httpd-2.4.46-lua-resume.patch deleted file mode 100644 index 1a22008..0000000 --- a/httpd-2.4.46-lua-resume.patch +++ /dev/null @@ -1,119 +0,0 @@ -diff --git a/modules/lua/config.m4 b/modules/lua/config.m4 -index 29fd563..abeba1c 100644 ---- a/modules/lua/config.m4 -+++ b/modules/lua/config.m4 -@@ -34,7 +34,7 @@ AC_DEFUN([CHECK_LUA_PATH], [dnl - fi - ]) - --dnl Check for Lua 5.3/5.2/5.1 Libraries -+dnl Check for Lua Libraries - dnl CHECK_LUA(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]) - dnl Sets: - dnl LUA_CFLAGS -@@ -44,7 +44,7 @@ AC_DEFUN([CHECK_LUA], - - AC_ARG_WITH( - lua, -- [AC_HELP_STRING([--with-lua=PATH],[Path to the Lua 5.3/5.2/5.1 prefix])], -+ [AC_HELP_STRING([--with-lua=PATH],[Path to the Lua installation prefix])], - lua_path="$withval", - :) - -diff --git a/modules/lua/mod_lua.c b/modules/lua/mod_lua.c -index 05f1e44..18b628c 100644 ---- a/modules/lua/mod_lua.c -+++ b/modules/lua/mod_lua.c -@@ -342,7 +342,7 @@ static apr_status_t lua_setup_filter_ctx(ap_filter_t* f, request_rec* r, lua_fil - { - apr_pool_t *pool; - ap_lua_vm_spec *spec; -- int n, rc; -+ int n, rc, nres; - lua_State *L; - lua_filter_ctx *ctx; - ap_lua_server_cfg *server_cfg = ap_get_module_config(r->server->module_config, -@@ -410,7 +410,7 @@ static apr_status_t lua_setup_filter_ctx(ap_filter_t* f, request_rec* r, lua_fil - /* If a Lua filter is interested in filtering a request, it must first do a yield, - * otherwise we'll assume that it's not interested and pretend we didn't find it. - */ -- rc = lua_resume(L, 1); -+ rc = lua_resume(L, 1, &nres); - if (rc == LUA_YIELD) { - if (f->frec->providers == NULL) { - /* Not wired by mod_filter */ -@@ -432,7 +432,7 @@ static apr_status_t lua_setup_filter_ctx(ap_filter_t* f, request_rec* r, lua_fil - static apr_status_t lua_output_filter_handle(ap_filter_t *f, apr_bucket_brigade *pbbIn) - { - request_rec *r = f->r; -- int rc; -+ int rc, nres; - lua_State *L; - lua_filter_ctx* ctx; - conn_rec *c = r->connection; -@@ -492,7 +492,7 @@ static apr_status_t lua_output_filter_handle(ap_filter_t *f, apr_bucket_brigade - lua_setglobal(L, "bucket"); - - /* If Lua yielded, it means we have something to pass on */ -- if (lua_resume(L, 0) == LUA_YIELD) { -+ if (lua_resume(L, 0, &nres) == LUA_YIELD && nres == 1) { - size_t olen; - const char* output = lua_tolstring(L, 1, &olen); - if (olen > 0) { -@@ -524,7 +524,7 @@ static apr_status_t lua_output_filter_handle(ap_filter_t *f, apr_bucket_brigade - apr_bucket *pbktEOS; - lua_pushnil(L); - lua_setglobal(L, "bucket"); -- if (lua_resume(L, 0) == LUA_YIELD) { -+ if (lua_resume(L, 0, &nres) == LUA_YIELD && nres == 1) { - apr_bucket *pbktOut; - size_t olen; - const char* output = lua_tolstring(L, 1, &olen); -@@ -558,7 +558,7 @@ static apr_status_t lua_input_filter_handle(ap_filter_t *f, - apr_off_t nBytes) - { - request_rec *r = f->r; -- int rc, lastCall = 0; -+ int rc, lastCall = 0, nres; - lua_State *L; - lua_filter_ctx* ctx; - conn_rec *c = r->connection; -@@ -621,7 +621,7 @@ static apr_status_t lua_input_filter_handle(ap_filter_t *f, - lua_setglobal(L, "bucket"); - - /* If Lua yielded, it means we have something to pass on */ -- if (lua_resume(L, 0) == LUA_YIELD) { -+ if (lua_resume(L, 0, &nres) == LUA_YIELD && nres == 1) { - size_t olen; - const char* output = lua_tolstring(L, 1, &olen); - pbktOut = apr_bucket_heap_create(output, olen, 0, c->bucket_alloc); -@@ -643,7 +643,7 @@ static apr_status_t lua_input_filter_handle(ap_filter_t *f, - apr_bucket *pbktEOS = apr_bucket_eos_create(c->bucket_alloc); - lua_pushnil(L); - lua_setglobal(L, "bucket"); -- if (lua_resume(L, 0) == LUA_YIELD) { -+ if (lua_resume(L, 0, &nres) == LUA_YIELD && nres == 1) { - apr_bucket *pbktOut; - size_t olen; - const char* output = lua_tolstring(L, 1, &olen); -diff --git a/modules/lua/mod_lua.h b/modules/lua/mod_lua.h -index 0e49cdc..72b4de7 100644 ---- a/modules/lua/mod_lua.h -+++ b/modules/lua/mod_lua.h -@@ -48,7 +48,15 @@ - #if LUA_VERSION_NUM > 501 - /* Load mode for lua_load() */ - #define lua_load(a,b,c,d) lua_load(a,b,c,d,NULL) --#define lua_resume(a,b) lua_resume(a, NULL, b) -+ -+#if LUA_VERSION_NUM > 503 -+#define lua_resume(a,b,c) lua_resume(a, NULL, b, c) -+#else -+/* ### For version < 5.4, assume that exactly one stack item is on the -+ * stack, which is what the code did before but seems dubious. */ -+#define lua_resume(a,b,c) (*(c) = 1, lua_resume(a, NULL, b)) -+#endif -+ - #define luaL_setfuncs_compat(a,b) luaL_setfuncs(a,b,0) - #else - #define lua_rawlen(L,i) lua_objlen(L, (i)) diff --git a/httpd-2.4.43-export.patch b/httpd-2.4.48-export.patch similarity index 93% rename from httpd-2.4.43-export.patch rename to httpd-2.4.48-export.patch index 0d9fd72..439f768 100644 --- a/httpd-2.4.43-export.patch +++ b/httpd-2.4.48-export.patch @@ -6,7 +6,7 @@ to do so indirectly. Upstream: https://svn.apache.org/r1861685 (as new default-off configure option) diff --git a/Makefile.in b/Makefile.in -index 9eeb5c7..8746a10 100644 +index 40c7076..ac98e5f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -4,8 +4,15 @@ CLEAN_SUBDIRS = test @@ -27,7 +27,7 @@ index 9eeb5c7..8746a10 100644 server/libmain.la \ $(BUILTIN_LIBS) \ diff --git a/server/Makefile.in b/server/Makefile.in -index 1fa3344..116850b 100644 +index 8111877..f00bb3f 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -12,7 +12,7 @@ LTLIBRARY_SOURCES = \ @@ -36,7 +36,7 @@ index 1fa3344..116850b 100644 util_charset.c util_cookies.c util_debug.c util_xml.c \ - util_filter.c util_pcre.c util_regex.c exports.c \ + util_filter.c util_pcre.c util_regex.c \ - scoreboard.c error_bucket.c protocol.c core.c request.c provider.c \ + scoreboard.c error_bucket.c protocol.c core.c request.c ssl.c provider.c \ eoc_bucket.c eor_bucket.c core_filters.c \ util_expr_parse.c util_expr_scan.c util_expr_eval.c diff --git a/server/main.c b/server/main.c diff --git a/httpd-2.4.43-r1842929+.patch b/httpd-2.4.48-r1842929+.patch similarity index 91% rename from httpd-2.4.43-r1842929+.patch rename to httpd-2.4.48-r1842929+.patch index b926195..f83a21d 100644 --- a/httpd-2.4.43-r1842929+.patch +++ b/httpd-2.4.48-r1842929+.patch @@ -1,8 +1,8 @@ diff --git a/Makefile.in b/Makefile.in -index 06b8c5a..9eeb5c7 100644 +index 6747aea..40c7076 100644 --- a/Makefile.in +++ b/Makefile.in -@@ -213,6 +213,7 @@ install-cgi: +@@ -233,6 +233,7 @@ install-cgi: install-other: @test -d $(DESTDIR)$(logfiledir) || $(MKINSTALLDIRS) $(DESTDIR)$(logfiledir) @test -d $(DESTDIR)$(runtimedir) || $(MKINSTALLDIRS) $(DESTDIR)$(runtimedir) @@ -11,7 +11,7 @@ index 06b8c5a..9eeb5c7 100644 file=apachecore.$$ext; \ if test -f $$file; then \ diff --git a/acinclude.m4 b/acinclude.m4 -index 95232f5..5d9d669 100644 +index b6ef442..98f1441 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -45,6 +45,7 @@ AC_DEFUN([APACHE_GEN_CONFIG_VARS],[ @@ -22,7 +22,7 @@ index 95232f5..5d9d669 100644 APACHE_SUBST(other_targets) APACHE_SUBST(progname) APACHE_SUBST(prefix) -@@ -688,6 +689,7 @@ AC_DEFUN([APACHE_EXPORT_ARGUMENTS],[ +@@ -665,6 +666,7 @@ AC_DEFUN([APACHE_EXPORT_ARGUMENTS],[ APACHE_SUBST_EXPANDED_ARG(runtimedir) APACHE_SUBST_EXPANDED_ARG(logfiledir) APACHE_SUBST_EXPANDED_ARG(proxycachedir) @@ -31,7 +31,7 @@ index 95232f5..5d9d669 100644 dnl diff --git a/configure.in b/configure.in -index a63eada..c8f9aa2 100644 +index 37346b2..f303784 100644 --- a/configure.in +++ b/configure.in @@ -41,7 +41,7 @@ dnl Something seems broken here. @@ -56,7 +56,7 @@ index 2b4a70c..e076f41 100644 #endif /* AP_CONFIG_LAYOUT_H */ diff --git a/include/http_config.h b/include/http_config.h -index f9c2d77..c229bc9 100644 +index 77657ae..384a90f 100644 --- a/include/http_config.h +++ b/include/http_config.h @@ -757,6 +757,14 @@ AP_DECLARE(char *) ap_server_root_relative(apr_pool_t *p, const char *fname); @@ -124,10 +124,10 @@ index addfd7e..2389f8f 100644 APR_HOOK_MIDDLE); dav_hook_find_liveprop(dav_fs_find_liveprop, NULL, NULL, APR_HOOK_MIDDLE); diff --git a/server/core.c b/server/core.c -index 3db9d61..79b2a82 100644 +index d135764..c2176b9 100644 --- a/server/core.c +++ b/server/core.c -@@ -129,6 +129,8 @@ AP_DECLARE_DATA int ap_main_state = AP_SQ_MS_INITIAL_STARTUP; +@@ -142,6 +142,8 @@ AP_DECLARE_DATA int ap_main_state = AP_SQ_MS_INITIAL_STARTUP; AP_DECLARE_DATA int ap_run_mode = AP_SQ_RM_UNKNOWN; AP_DECLARE_DATA int ap_config_generation = 0; @@ -136,7 +136,7 @@ index 3db9d61..79b2a82 100644 static void *create_core_dir_config(apr_pool_t *a, char *dir) { core_dir_config *conf; -@@ -1409,12 +1411,15 @@ AP_DECLARE(const char *) ap_resolve_env(apr_pool_t *p, const char * word) +@@ -1444,13 +1446,16 @@ AP_DECLARE(const char *) ap_resolve_env(apr_pool_t *p, const char * word) return res_buf; } @@ -147,6 +147,7 @@ index 3db9d61..79b2a82 100644 ap_server_config_defines = saved_server_config_defines; saved_server_config_defines = NULL; server_config_defined_vars = NULL; + ap_runtime_dir = NULL; - return OK; + core_state_dir = NULL; + @@ -154,7 +155,7 @@ index 3db9d61..79b2a82 100644 } /* -@@ -3120,6 +3125,24 @@ static const char *set_runtime_dir(cmd_parms *cmd, void *dummy, const char *arg) +@@ -3220,6 +3225,24 @@ static const char *set_runtime_dir(cmd_parms *cmd, void *dummy, const char *arg) return NULL; } @@ -179,7 +180,7 @@ index 3db9d61..79b2a82 100644 static const char *set_timeout(cmd_parms *cmd, void *dummy, const char *arg) { const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_CONTEXT); -@@ -4414,6 +4437,8 @@ AP_INIT_TAKE1("ServerRoot", set_server_root, NULL, RSRC_CONF | EXEC_ON_READ, +@@ -4521,6 +4544,8 @@ AP_INIT_TAKE1("ServerRoot", set_server_root, NULL, RSRC_CONF | EXEC_ON_READ, "Common directory of server-related files (logs, confs, etc.)"), AP_INIT_TAKE1("DefaultRuntimeDir", set_runtime_dir, NULL, RSRC_CONF | EXEC_ON_READ, "Common directory for run-time files (shared memory, locks, etc.)"), @@ -188,7 +189,7 @@ index 3db9d61..79b2a82 100644 AP_INIT_TAKE1("ErrorLog", set_server_string_slot, (void *)APR_OFFSETOF(server_rec, error_fname), RSRC_CONF, "The filename of the error log"), -@@ -4941,8 +4966,7 @@ static int core_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptem +@@ -5055,8 +5080,7 @@ static int core_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptem if (!saved_server_config_defines) init_config_defines(pconf); @@ -198,7 +199,7 @@ index 3db9d61..79b2a82 100644 ap_regcomp_set_default_cflags(AP_REG_DEFAULT); -@@ -5170,6 +5194,27 @@ AP_DECLARE(int) ap_state_query(int query) +@@ -5303,6 +5327,27 @@ AP_DECLARE(int) ap_state_query(int query) } } diff --git a/httpd.spec b/httpd.spec index 6f5ef66..432c1f2 100644 --- a/httpd.spec +++ b/httpd.spec @@ -12,8 +12,8 @@ Summary: Apache HTTP Server Name: httpd -Version: 2.4.46 -Release: 9%{?dist} +Version: 2.4.48 +Release: 1%{?dist} URL: https://httpd.apache.org/ Source0: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2 Source1: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2.asc @@ -67,9 +67,9 @@ Patch3: httpd-2.4.43-deplibs.patch # Needed for socket activation and mod_systemd patch Patch19: httpd-2.4.43-detect-systemd.patch # Features/functional changes -Patch21: httpd-2.4.43-r1842929+.patch +Patch21: httpd-2.4.48-r1842929+.patch Patch22: httpd-2.4.43-mod_systemd.patch -Patch23: httpd-2.4.43-export.patch +Patch23: httpd-2.4.48-export.patch Patch24: httpd-2.4.43-corelimit.patch Patch25: httpd-2.4.43-selinux.patch Patch26: httpd-2.4.43-gettid.patch @@ -82,14 +82,11 @@ Patch39: httpd-2.4.43-sslprotdefault.patch Patch40: httpd-2.4.43-r1861269.patch Patch41: httpd-2.4.43-r1861793+.patch Patch42: httpd-2.4.43-r1828172+.patch -Patch43: httpd-2.4.43-sslcoalesce.patch -Patch44: httpd-2.4.46-lua-resume.patch Patch45: httpd-2.4.43-logjournal.patch # Bug fixes # https://bugzilla.redhat.com/show_bug.cgi?id=1397243 Patch60: httpd-2.4.43-enable-sslv3.patch -Patch62: httpd-2.4.43-r1870095+.patch Patch63: httpd-2.4.46-htcacheclean-dont-break.patch # Security fixes @@ -235,12 +232,9 @@ written in the Lua programming language. %patch40 -p1 -b .r1861269 %patch41 -p1 -b .r1861793+ %patch42 -p1 -b .r1828172+ -%patch43 -p1 -b .sslcoalesce -%patch44 -p1 -b .luaresume %patch45 -p1 -b .logjournal %patch60 -p1 -b .enable-sslv3 -%patch62 -p1 -b .r1870095 %patch63 -p1 -b .htcacheclean-dont-break # Patch in the vendor string @@ -779,6 +773,10 @@ exit $rv %{_rpmconfigdir}/macros.d/macros.httpd %changelog +* Wed Jun 02 2021 Luboš Uhliarik - 2.4.48-1 +- new version 2.4.48 +- Resolves: #1964746 - httpd-2.4.48 is available + * Mon Feb 01 2021 Lubos Uhliarik - 2.4.46-9 - Resolves: #1914182 - RFE: CustomLog should be able to use journald diff --git a/sources b/sources index a7871fb..5e6cb0c 100644 --- a/sources +++ b/sources @@ -1,3 +1,3 @@ -SHA512 (httpd-2.4.46.tar.bz2) = 5936784bb662e9d8a4f7fe38b70c043b468114d931cd10ea831bfe74461ea5856b64f88f42c567ab791fc8907640a99884ba4b6a600f86d661781812735b6f13 -SHA512 (httpd-2.4.46.tar.bz2.asc) = 1f54c20d1aeedb7c745eb72acd79e1ed61d547b22c3dbe53cd3274ed3d897543cd8c49181d4b15d79c12755746cf0a2464d620f69e254ac3f998760133094df0 -SHA512 (KEYS) = b776ca20863f8d9e4f66e8b56cbe020de34af5b268e93776d482392171f0e0aeee4f8d74477d128dc9fd24b30bbe33b39439964f1bd22a99782f1e4a08c85056 +SHA512 (httpd-2.4.48.tar.bz2) = 6c250626f1e7d10428a92d984fd48ff841effcc8705f7816ab71b681bbd51d0012ad158dcd13763fe7d630311f2de258b27574603140d648be42796ab8326724 +SHA512 (httpd-2.4.48.tar.bz2.asc) = 9f125de75107b04dd01f71e9e233b1602658b49e38371931b98dc1092be8df05cf7243b5564fa2f56f46544bef61a54a721dee5ca17ce823a2302a7c3698a195 +SHA512 (KEYS) = 7ab66c64eaa4a152e88a913993c8ea0d9c46fd5865788e7b32a9619784d245cef8bddd9700368e3d63ce88ed94df8933e5892878523dc0fce697331136bb829e From 948d29f95248a8c30b93b8e24ed3509bd0fe8e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Uhliarik?= Date: Fri, 8 Oct 2021 13:58:49 +0200 Subject: [PATCH 2/3] new version 2.4.51 --- .gitignore | 4 +- httpd-2.4.43-sslmultiproxy.patch | 118 +++++++++++++++++++++++++++++++ httpd.spec | 69 +++--------------- sources | 4 +- welcome.conf | 3 +- 5 files changed, 130 insertions(+), 68 deletions(-) create mode 100644 httpd-2.4.43-sslmultiproxy.patch diff --git a/.gitignore b/.gitignore index af7dee4..12fe79c 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,4 @@ x86_64 /httpd-2.4.43.tar.bz2.asc /KEYS /httpd-2.4.46.tar.bz2.asc -/httpd-2.4.48.tar.bz2.asc -/httpd-2.4.49.tar.bz2.asc -/httpd-2.4.50.tar.bz2.asc +/httpd-2.4.51.tar.bz2.asc diff --git a/httpd-2.4.43-sslmultiproxy.patch b/httpd-2.4.43-sslmultiproxy.patch new file mode 100644 index 0000000..349c4ae --- /dev/null +++ b/httpd-2.4.43-sslmultiproxy.patch @@ -0,0 +1,118 @@ +diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c +index 12617b2..0fe7464 100644 +--- a/modules/ssl/mod_ssl.c ++++ b/modules/ssl/mod_ssl.c +@@ -459,6 +459,10 @@ static int ssl_hook_pre_config(apr_pool_t *pconf, + return OK; + } + ++static APR_OPTIONAL_FN_TYPE(ssl_engine_disable) *othermod_engine_disable; ++static APR_OPTIONAL_FN_TYPE(ssl_engine_set) *othermod_engine_set; ++ ++ + static SSLConnRec *ssl_init_connection_ctx(conn_rec *c, + ap_conf_vector_t *per_dir_config, + int new_proxy) +@@ -466,6 +470,10 @@ static SSLConnRec *ssl_init_connection_ctx(conn_rec *c, + SSLConnRec *sslconn = myConnConfig(c); + int need_setup = 0; + ++ if (othermod_engine_disable) { ++ othermod_engine_disable(c); ++ } ++ + /* mod_proxy's (r->)per_dir_config has the lifetime of the request, thus + * it uses ssl_engine_set() to reset sslconn->dc when reusing SSL backend + * connections, so we must fall through here. But in the case where we are +@@ -544,6 +552,10 @@ static int ssl_engine_set(conn_rec *c, + { + SSLConnRec *sslconn; + int status; ++ ++ if (othermod_engine_set) { ++ return othermod_engine_set(c, per_dir_config, proxy, enable); ++ } + + if (proxy) { + sslconn = ssl_init_connection_ctx(c, per_dir_config, 1); +@@ -572,12 +584,18 @@ static int ssl_engine_set(conn_rec *c, + + static int ssl_proxy_enable(conn_rec *c) + { +- return ssl_engine_set(c, NULL, 1, 1); ++ if (othermod_engine_set) ++ return othermod_engine_set(c, NULL, 1, 1); ++ else ++ return ssl_engine_set(c, NULL, 1, 1); + } + + static int ssl_engine_disable(conn_rec *c) + { +- return ssl_engine_set(c, NULL, 0, 0); ++ if (othermod_engine_set) ++ return othermod_engine_set(c, NULL, 0, 0); ++ else ++ return ssl_engine_set(c, NULL, 0, 0); + } + + int ssl_init_ssl_connection(conn_rec *c, request_rec *r) +@@ -753,6 +771,9 @@ static void ssl_register_hooks(apr_pool_t *p) + APR_HOOK_MIDDLE); + + ssl_var_register(p); ++ ++ othermod_engine_disable = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable); ++ othermod_engine_set = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_set); + + 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 5724f18..81c56ba 100644 +--- a/modules/ssl/ssl_engine_vars.c ++++ b/modules/ssl/ssl_engine_vars.c +@@ -54,6 +54,8 @@ static char *ssl_var_lookup_ssl_cipher(apr_pool_t *p, SSLConnRec *sslconn, char + static void ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize); + 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) + { +@@ -68,7 +70,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 +141,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); +@@ -271,6 +278,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/httpd.spec b/httpd.spec index d15c8bb..d4f88af 100644 --- a/httpd.spec +++ b/httpd.spec @@ -12,7 +12,7 @@ Summary: Apache HTTP Server Name: httpd -Version: 2.4.50 +Version: 2.4.51 Release: 1%{?dist} URL: https://httpd.apache.org/ Source0: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2 @@ -60,7 +60,6 @@ Source44: httpd@.service Source45: config.layout Source46: apachectl.sh Source47: apachectl.xml -Source48: apache-poweredby.png # build/scripts patches Patch2: httpd-2.4.43-apxs.patch @@ -75,20 +74,19 @@ Patch24: httpd-2.4.43-corelimit.patch Patch25: httpd-2.4.43-selinux.patch Patch26: httpd-2.4.43-gettid.patch Patch27: httpd-2.4.43-icons.patch -Patch28: httpd-2.4.48-openssl3.patch Patch30: httpd-2.4.43-cachehardmax.patch +Patch31: httpd-2.4.43-sslmultiproxy.patch Patch34: httpd-2.4.43-socket-activation.patch Patch38: httpd-2.4.43-sslciphdefault.patch Patch39: httpd-2.4.43-sslprotdefault.patch Patch40: httpd-2.4.43-r1861269.patch Patch41: httpd-2.4.43-r1861793+.patch -Patch42: httpd-2.4.48-r1828172+.patch +Patch42: httpd-2.4.43-r1828172+.patch Patch45: httpd-2.4.43-logjournal.patch # Bug fixes # https://bugzilla.redhat.com/show_bug.cgi?id=1397243 Patch60: httpd-2.4.43-enable-sslv3.patch -Patch61: httpd-2.4.48-r1878890.patch Patch63: httpd-2.4.46-htcacheclean-dont-break.patch # Security fixes @@ -99,7 +97,7 @@ BuildRequires: perl-interpreter, perl-generators, systemd-devel BuildRequires: zlib-devel, libselinux-devel, lua-devel, brotli-devel BuildRequires: apr-devel >= 1.5.0, apr-util-devel >= 1.5.0, pcre-devel >= 5.0 BuildRequires: gnupg2 -Requires: /etc/mime.types, system-logos(httpd-logo-ng) +Requires: /etc/mime.types, system-logos-httpd Provides: webserver Provides: mod_dav = %{version}-%{release}, httpd-suexec = %{version}-%{release} Provides: httpd-mmn = %{mmn}, httpd-mmn = %{mmnisa} @@ -168,8 +166,6 @@ Requires: httpd = 0:%{version}-%{release}, httpd-mmn = %{mmnisa} Requires: sscg >= 2.2.0, /usr/bin/hostname # Require an OpenSSL which supports PROFILE=SYSTEM Conflicts: openssl-libs < 1:1.0.1h-4 -# mod_ssl/mod_nss cannot both be loaded simultaneously -Conflicts: mod_nss %description -n mod_ssl The mod_ssl module provides strong cryptography for the Apache HTTP @@ -228,8 +224,8 @@ written in the Lua programming language. %patch25 -p1 -b .selinux %patch26 -p1 -b .gettid %patch27 -p1 -b .icons -%patch28 -p1 -b .openssl3 %patch30 -p1 -b .cachehardmax +#patch31 -p1 -b .sslmultiproxy %patch34 -p1 -b .socketactivation %patch38 -p1 -b .sslciphdefault %patch39 -p1 -b .sslprotdefault @@ -239,7 +235,6 @@ written in the Lua programming language. %patch45 -p1 -b .logjournal %patch60 -p1 -b .enable-sslv3 -%patch61 -p1 -b .r1878890 %patch63 -p1 -b .htcacheclean-dont-break # Patch in the vendor string @@ -267,9 +262,6 @@ if test "x${vmmn}" != "x%{mmn}"; then exit 1 fi -# A new logo which comes together with a new test page -cp %{SOURCE48} ./docs/icons/apache_pb3.png - # Provide default layout cp $RPM_SOURCE_DIR/config.layout . @@ -456,7 +448,7 @@ EOF # Handle contentdir mkdir $RPM_BUILD_ROOT%{contentdir}/noindex \ $RPM_BUILD_ROOT%{contentdir}/server-status -ln -s ../../testpage/index.html \ +ln -s ../../fedora-testpage/index.html \ $RPM_BUILD_ROOT%{contentdir}/noindex/index.html install -m 644 -p docs/server-status/* \ $RPM_BUILD_ROOT%{contentdir}/server-status @@ -485,12 +477,6 @@ rm -v $RPM_BUILD_ROOT%{docroot}/html/*.html \ ln -s ../../pixmaps/poweredby.png \ $RPM_BUILD_ROOT%{contentdir}/icons/poweredby.png -# Symlink for the system logo -%if 0%{?rhel} >= 9 -ln -s ../../pixmaps/system-noindex-logo.png \ - $RPM_BUILD_ROOT%{contentdir}/icons/system_noindex_logo.png -%endif - # symlinks for /etc/httpd rmdir $RPM_BUILD_ROOT/etc/httpd/{state,run} ln -s ../..%{_localstatedir}/log/httpd $RPM_BUILD_ROOT/etc/httpd/logs @@ -787,47 +773,8 @@ exit $rv %{_rpmconfigdir}/macros.d/macros.httpd %changelog -* Tue Oct 05 2021 Luboš Uhliarik - 2.4.50-1 -- new version 2.4.50 - -* Wed Sep 22 2021 Luboš Uhliarik - 2.4.49-3 -- Rebuilt for CI testing - -* Thu Sep 16 2021 Luboš Uhliarik - 2.4.49-1 -- new version 2.4.49 (#2004776) - -* Tue Sep 14 2021 Sahana Prasad - 2.4.48-8 -- Rebuilt with OpenSSL 3.0.0 - -* Fri Aug 06 2021 Luboš Uhliarik - 2.4.48-7 -- add symlink to system logo for noindex test page - -* Fri Aug 6 2021 Joe Orton - 2.4.48-4 -- add OpenSSL 3.x compatibility patch - -* Thu Jul 22 2021 Fedora Release Engineering - 2.4.48-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild - -* Fri Jul 16 2021 Joe Orton - 2.4.48-2 -- mod_cgi/mod_cgid: update to unification from trunk -- httpd.conf: add note on care with Listen and starting at boot - -* Wed Jun 02 2021 Luboš Uhliarik - 2.4.48-1 -- new version 2.4.48 -- Resolves: #1964746 - httpd-2.4.48 is available - -* Mon May 03 2021 Lubos Uhliarik - 2.4.46-13 -- Related: #1934739 - Apache trademark update - new logo - -* Fri Apr 9 2021 Joe Orton - 2.4.46-12 -- use OOMPolicy=continue in httpd.service, httpd@.service (#1947475) - -* Wed Mar 31 2021 Lubos Uhliarik - 2.4.46-11 -- Resolves: #1934739 - Apache trademark update - new logo - -* Tue Feb 23 2021 Joe Orton - 2.4.46-10 -- add Conflicts: with mod_nss -- drop use of apr_ldap_rebind (r1878890, #1847585) +* Fri Oct 08 2021 Luboš Uhliarik - 2.4.51-1 +- new version 2.4.51 * Mon Feb 01 2021 Lubos Uhliarik - 2.4.46-9 - Resolves: #1914182 - RFE: CustomLog should be able to use journald diff --git a/sources b/sources index 63a8c16..edbf616 100644 --- a/sources +++ b/sources @@ -1,3 +1,3 @@ -SHA512 (httpd-2.4.50.tar.bz2) = b1afbaf44e503b822ff2b443881dcb44a93aa55d496f88ae399a2e7def05f78590f266a16da1f2c0aac88e463b76fba20843b1e20a102e76c8269de6fae3e158 -SHA512 (httpd-2.4.50.tar.bz2.asc) = 31ec3cbf342905f63fc070ae51103a695736a0fc5689d38845a7802fa6b48d86bafd5afcf57f7bbee4435691093326ec5f07a904fd3fa877e0453a3830425776 +SHA512 (httpd-2.4.51.tar.bz2) = 9fb07c4b176f5c0485a143e2b1bb1085345ca9120b959974f68c37a8911a57894d2cb488b1b42fdf3102860b99e890204f5e9fa7ae3828b481119c563812cc66 +SHA512 (httpd-2.4.51.tar.bz2.asc) = c63f2b08eb0b7e688c4a89b4be1d968c9e4a3f09714ffc4fb9b2210b6694b8c90f4067aec63601ec41987507bba8dfcef15f54b8c0707cc49414c9c76dd5d8ce SHA512 (KEYS) = 88c848b7ab9e4915d6625dcad3e8328673b0448f2ce76f2c44eecc612cf6afbce3287a4ee7219a44c6fcc61d5ecb2a1a8545456a4a16b90400263d7249cbf192 diff --git a/welcome.conf b/welcome.conf index 232c251..b279c2f 100644 --- a/welcome.conf +++ b/welcome.conf @@ -16,5 +16,4 @@ Alias /.noindex.html /usr/share/httpd/noindex/index.html -Alias /poweredby.png /usr/share/httpd/icons/apache_pb3.png -Alias /system_noindex_logo.png /usr/share/httpd/icons/system_noindex_logo.png +Alias /poweredby.png /usr/share/httpd/icons/apache_pb2.png From 6c0da47cfc3c50d8a1ab65093674cc190f402764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Uhliarik?= Date: Fri, 8 Oct 2021 14:46:35 +0200 Subject: [PATCH 3/3] Add missing patch file --- httpd-2.4.43-r1828172+.patch | 1413 ++++++++++++++++++++++++++++++++++ 1 file changed, 1413 insertions(+) create mode 100644 httpd-2.4.43-r1828172+.patch diff --git a/httpd-2.4.43-r1828172+.patch b/httpd-2.4.43-r1828172+.patch new file mode 100644 index 0000000..3487600 --- /dev/null +++ b/httpd-2.4.43-r1828172+.patch @@ -0,0 +1,1413 @@ +diff --git a/modules/generators/cgi_common.h b/modules/generators/cgi_common.h +new file mode 100644 +index 0000000..85c9685 +--- /dev/null ++++ b/modules/generators/cgi_common.h +@@ -0,0 +1,359 @@ ++/* 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. ++ */ ++ ++#include "apr.h" ++#include "apr_strings.h" ++#include "apr_buckets.h" ++#include "apr_lib.h" ++#include "apr_poll.h" ++ ++#define APR_WANT_STRFUNC ++#define APR_WANT_MEMFUNC ++#include "apr_want.h" ++ ++#include "httpd.h" ++#include "util_filter.h" ++ ++static void discard_script_output(apr_bucket_brigade *bb) ++{ ++ apr_bucket *e; ++ const char *buf; ++ apr_size_t len; ++ ++ for (e = APR_BRIGADE_FIRST(bb); ++ e != APR_BRIGADE_SENTINEL(bb) && !APR_BUCKET_IS_EOS(e); ++ e = APR_BRIGADE_FIRST(bb)) ++ { ++ if (apr_bucket_read(e, &buf, &len, APR_BLOCK_READ)) { ++ break; ++ } ++ apr_bucket_delete(e); ++ } ++} ++ ++#ifdef WANT_CGI_BUCKET ++/* A CGI bucket type is needed to catch any output to stderr from the ++ * script; see PR 22030. */ ++static const apr_bucket_type_t bucket_type_cgi; ++ ++struct cgi_bucket_data { ++ apr_pollset_t *pollset; ++ request_rec *r; ++ apr_interval_time_t timeout; ++}; ++ ++/* Create a CGI bucket using pipes from script stdout 'out' ++ * and stderr 'err', for request 'r'. */ ++static apr_bucket *cgi_bucket_create(request_rec *r, ++ apr_interval_time_t timeout, ++ apr_file_t *out, apr_file_t *err, ++ apr_bucket_alloc_t *list) ++{ ++ apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); ++ apr_status_t rv; ++ apr_pollfd_t fd; ++ struct cgi_bucket_data *data = apr_palloc(r->pool, sizeof *data); ++ ++ /* Disable APR timeout handling since we'll use poll() entirely. */ ++ apr_file_pipe_timeout_set(out, 0); ++ apr_file_pipe_timeout_set(err, 0); ++ ++ APR_BUCKET_INIT(b); ++ b->free = apr_bucket_free; ++ b->list = list; ++ b->type = &bucket_type_cgi; ++ b->length = (apr_size_t)(-1); ++ b->start = -1; ++ ++ /* Create the pollset */ ++ rv = apr_pollset_create(&data->pollset, 2, r->pool, 0); ++ if (rv != APR_SUCCESS) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01217) ++ "apr_pollset_create(); check system or user limits"); ++ return NULL; ++ } ++ ++ fd.desc_type = APR_POLL_FILE; ++ fd.reqevents = APR_POLLIN; ++ fd.p = r->pool; ++ fd.desc.f = out; /* script's stdout */ ++ fd.client_data = (void *)1; ++ rv = apr_pollset_add(data->pollset, &fd); ++ if (rv != APR_SUCCESS) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01218) ++ "apr_pollset_add(); check system or user limits"); ++ return NULL; ++ } ++ ++ fd.desc.f = err; /* script's stderr */ ++ fd.client_data = (void *)2; ++ rv = apr_pollset_add(data->pollset, &fd); ++ if (rv != APR_SUCCESS) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01219) ++ "apr_pollset_add(); check system or user limits"); ++ return NULL; ++ } ++ ++ data->r = r; ++ data->timeout = timeout; ++ b->data = data; ++ return b; ++} ++ ++/* Create a duplicate CGI bucket using given bucket data */ ++static apr_bucket *cgi_bucket_dup(struct cgi_bucket_data *data, ++ apr_bucket_alloc_t *list) ++{ ++ apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); ++ APR_BUCKET_INIT(b); ++ b->free = apr_bucket_free; ++ b->list = list; ++ b->type = &bucket_type_cgi; ++ b->length = (apr_size_t)(-1); ++ b->start = -1; ++ b->data = data; ++ return b; ++} ++ ++/* Handle stdout from CGI child. Duplicate of logic from the _read ++ * method of the real APR pipe bucket implementation. */ ++static apr_status_t cgi_read_stdout(apr_bucket *a, apr_file_t *out, ++ const char **str, apr_size_t *len) ++{ ++ char *buf; ++ apr_status_t rv; ++ ++ *str = NULL; ++ *len = APR_BUCKET_BUFF_SIZE; ++ buf = apr_bucket_alloc(*len, a->list); /* XXX: check for failure? */ ++ ++ rv = apr_file_read(out, buf, len); ++ ++ if (rv != APR_SUCCESS && rv != APR_EOF) { ++ apr_bucket_free(buf); ++ return rv; ++ } ++ ++ if (*len > 0) { ++ struct cgi_bucket_data *data = a->data; ++ apr_bucket_heap *h; ++ ++ /* Change the current bucket to refer to what we read */ ++ a = apr_bucket_heap_make(a, buf, *len, apr_bucket_free); ++ h = a->data; ++ h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */ ++ *str = buf; ++ APR_BUCKET_INSERT_AFTER(a, cgi_bucket_dup(data, a->list)); ++ } ++ else { ++ apr_bucket_free(buf); ++ a = apr_bucket_immortal_make(a, "", 0); ++ *str = a->data; ++ } ++ return rv; ++} ++ ++/* Read method of CGI bucket: polls on stderr and stdout of the child, ++ * sending any stderr output immediately away to the error log. */ ++static apr_status_t cgi_bucket_read(apr_bucket *b, const char **str, ++ apr_size_t *len, apr_read_type_e block) ++{ ++ struct cgi_bucket_data *data = b->data; ++ apr_interval_time_t timeout = 0; ++ apr_status_t rv; ++ int gotdata = 0; ++ ++ if (block != APR_NONBLOCK_READ) { ++ timeout = data->timeout > 0 ? data->timeout : data->r->server->timeout; ++ } ++ ++ do { ++ const apr_pollfd_t *results; ++ apr_int32_t num; ++ ++ rv = apr_pollset_poll(data->pollset, timeout, &num, &results); ++ if (APR_STATUS_IS_TIMEUP(rv)) { ++ if (timeout) { ++ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, data->r, APLOGNO(01220) ++ "Timeout waiting for output from CGI script %s", ++ data->r->filename); ++ return rv; ++ } ++ else { ++ return APR_EAGAIN; ++ } ++ } ++ else if (APR_STATUS_IS_EINTR(rv)) { ++ continue; ++ } ++ else if (rv != APR_SUCCESS) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, data->r, APLOGNO(01221) ++ "poll failed waiting for CGI child"); ++ return rv; ++ } ++ ++ for (; num; num--, results++) { ++ if (results[0].client_data == (void *)1) { ++ /* stdout */ ++ rv = cgi_read_stdout(b, results[0].desc.f, str, len); ++ if (APR_STATUS_IS_EOF(rv)) { ++ rv = APR_SUCCESS; ++ } ++ gotdata = 1; ++ } else { ++ /* stderr */ ++ apr_status_t rv2 = log_script_err(data->r, results[0].desc.f); ++ if (APR_STATUS_IS_EOF(rv2)) { ++ apr_pollset_remove(data->pollset, &results[0]); ++ } ++ } ++ } ++ ++ } while (!gotdata); ++ ++ return rv; ++} ++ ++static const apr_bucket_type_t bucket_type_cgi = { ++ "CGI", 5, APR_BUCKET_DATA, ++ apr_bucket_destroy_noop, ++ cgi_bucket_read, ++ apr_bucket_setaside_notimpl, ++ apr_bucket_split_notimpl, ++ apr_bucket_copy_notimpl ++}; ++ ++#endif /* WANT_CGI_BUCKET */ ++ ++/* Handle the CGI response output, having set up the brigade with the ++ * CGI or PIPE bucket as appropriate. */ ++static int cgi_handle_response(request_rec *r, int nph, apr_bucket_brigade *bb, ++ apr_interval_time_t timeout, cgi_server_conf *conf, ++ char *logdata, apr_file_t *script_err) ++{ ++ apr_status_t rv; ++ ++ /* Handle script return... */ ++ if (!nph) { ++ const char *location; ++ char sbuf[MAX_STRING_LEN]; ++ int ret; ++ ++ if ((ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf, ++ APLOG_MODULE_INDEX))) ++ { ++ ret = log_script(r, conf, ret, logdata, sbuf, bb, script_err); ++ ++ /* ++ * ret could be HTTP_NOT_MODIFIED in the case that the CGI script ++ * does not set an explicit status and ap_meets_conditions, which ++ * is called by ap_scan_script_header_err_brigade, detects that ++ * the conditions of the requests are met and the response is ++ * not modified. ++ * In this case set r->status and return OK in order to prevent ++ * running through the error processing stack as this would ++ * break with mod_cache, if the conditions had been set by ++ * mod_cache itself to validate a stale entity. ++ * BTW: We circumvent the error processing stack anyway if the ++ * CGI script set an explicit status code (whatever it is) and ++ * the only possible values for ret here are: ++ * ++ * HTTP_NOT_MODIFIED (set by ap_meets_conditions) ++ * HTTP_PRECONDITION_FAILED (set by ap_meets_conditions) ++ * HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the ++ * processing of the response of the CGI script, e.g broken headers ++ * or a crashed CGI process). ++ */ ++ if (ret == HTTP_NOT_MODIFIED) { ++ r->status = ret; ++ return OK; ++ } ++ ++ return ret; ++ } ++ ++ location = apr_table_get(r->headers_out, "Location"); ++ ++ if (location && r->status == 200) { ++ /* For a redirect whether internal or not, discard any ++ * remaining stdout from the script, and log any remaining ++ * stderr output, as normal. */ ++ discard_script_output(bb); ++ apr_brigade_destroy(bb); ++ ++ if (script_err) { ++ apr_file_pipe_timeout_set(script_err, timeout); ++ log_script_err(r, script_err); ++ } ++ } ++ ++ if (location && location[0] == '/' && r->status == 200) { ++ /* This redirect needs to be a GET no matter what the original ++ * method was. ++ */ ++ r->method = "GET"; ++ r->method_number = M_GET; ++ ++ /* We already read the message body (if any), so don't allow ++ * the redirected request to think it has one. We can ignore ++ * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. ++ */ ++ apr_table_unset(r->headers_in, "Content-Length"); ++ ++ ap_internal_redirect_handler(location, r); ++ return OK; ++ } ++ else if (location && r->status == 200) { ++ /* XXX: Note that if a script wants to produce its own Redirect ++ * body, it now has to explicitly *say* "Status: 302" ++ */ ++ discard_script_output(bb); ++ apr_brigade_destroy(bb); ++ return HTTP_MOVED_TEMPORARILY; ++ } ++ ++ rv = ap_pass_brigade(r->output_filters, bb); ++ } ++ else /* nph */ { ++ struct ap_filter_t *cur; ++ ++ /* get rid of all filters up through protocol... since we ++ * haven't parsed off the headers, there is no way they can ++ * work ++ */ ++ ++ cur = r->proto_output_filters; ++ while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION) { ++ cur = cur->next; ++ } ++ r->output_filters = r->proto_output_filters = cur; ++ ++ rv = ap_pass_brigade(r->output_filters, bb); ++ } ++ ++ /* don't soak up script output if errors occurred writing it ++ * out... otherwise, we prolong the life of the script when the ++ * connection drops or we stopped sending output for some other ++ * reason */ ++ if (script_err && rv == APR_SUCCESS && !r->connection->aborted) { ++ apr_file_pipe_timeout_set(script_err, timeout); ++ log_script_err(r, script_err); ++ } ++ ++ if (script_err) apr_file_close(script_err); ++ ++ return OK; /* NOT r->status, even if it has changed. */ ++} +diff --git a/modules/generators/config5.m4 b/modules/generators/config5.m4 +index bf29521..0863553 100644 +--- a/modules/generators/config5.m4 ++++ b/modules/generators/config5.m4 +@@ -78,4 +78,15 @@ fi + + APR_ADDTO(INCLUDES, [-I\$(top_srcdir)/$modpath_current]) + ++AC_ARG_ENABLE(cgid-fdpassing, ++ [APACHE_HELP_STRING(--enable-cgid-fdpassing,Enable experimental mod_cgid support for fd passing)], ++ [if test "$enableval" = "yes"; then ++ AC_CHECK_DECL(CMSG_DATA, ++ [AC_DEFINE([HAVE_CGID_FDPASSING], 1, [Enable FD passing support in mod_cgid])], ++ [AC_MSG_ERROR([cannot support mod_cgid fd-passing on this system])], [ ++#include ++#include ]) ++ fi ++]) ++ + APACHE_MODPATH_FINISH +diff --git a/modules/generators/mod_cgi.c b/modules/generators/mod_cgi.c +index 7e4b126..f438b35 100644 +--- a/modules/generators/mod_cgi.c ++++ b/modules/generators/mod_cgi.c +@@ -92,6 +92,10 @@ typedef struct { + apr_size_t bufbytes; + } cgi_server_conf; + ++typedef struct { ++ apr_interval_time_t timeout; ++} cgi_dirconf; ++ + static void *create_cgi_config(apr_pool_t *p, server_rec *s) + { + cgi_server_conf *c = +@@ -112,6 +116,12 @@ static void *merge_cgi_config(apr_pool_t *p, void *basev, void *overridesv) + return overrides->logname ? overrides : base; + } + ++static void *create_cgi_dirconf(apr_pool_t *p, char *dummy) ++{ ++ cgi_dirconf *c = (cgi_dirconf *) apr_pcalloc(p, sizeof(cgi_dirconf)); ++ return c; ++} ++ + static const char *set_scriptlog(cmd_parms *cmd, void *dummy, const char *arg) + { + server_rec *s = cmd->server; +@@ -150,6 +160,17 @@ static const char *set_scriptlog_buffer(cmd_parms *cmd, void *dummy, + return NULL; + } + ++static const char *set_script_timeout(cmd_parms *cmd, void *dummy, const char *arg) ++{ ++ cgi_dirconf *dc = dummy; ++ ++ if (ap_timeout_parameter_parse(arg, &dc->timeout, "s") != APR_SUCCESS) { ++ return "CGIScriptTimeout has wrong format"; ++ } ++ ++ return NULL; ++} ++ + static const command_rec cgi_cmds[] = + { + AP_INIT_TAKE1("ScriptLog", set_scriptlog, NULL, RSRC_CONF, +@@ -158,6 +179,9 @@ AP_INIT_TAKE1("ScriptLogLength", set_scriptlog_length, NULL, RSRC_CONF, + "the maximum length (in bytes) of the script debug log"), + AP_INIT_TAKE1("ScriptLogBuffer", set_scriptlog_buffer, NULL, RSRC_CONF, + "the maximum size (in bytes) to record of a POST request"), ++AP_INIT_TAKE1("CGIScriptTimeout", set_script_timeout, NULL, RSRC_CONF | ACCESS_CONF, ++ "The amount of time to wait between successful reads from " ++ "the CGI script, in seconds."), + {NULL} + }; + +@@ -466,23 +490,26 @@ static apr_status_t run_cgi_child(apr_file_t **script_out, + apr_filepath_name_get(r->filename)); + } + else { ++ cgi_dirconf *dc = ap_get_module_config(r->per_dir_config, &cgi_module); ++ apr_interval_time_t timeout = dc->timeout > 0 ? dc->timeout : r->server->timeout; ++ + apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT); + + *script_in = procnew->out; + if (!*script_in) + return APR_EBADF; +- apr_file_pipe_timeout_set(*script_in, r->server->timeout); ++ apr_file_pipe_timeout_set(*script_in, timeout); + + if (e_info->prog_type == RUN_AS_CGI) { + *script_out = procnew->in; + if (!*script_out) + return APR_EBADF; +- apr_file_pipe_timeout_set(*script_out, r->server->timeout); ++ apr_file_pipe_timeout_set(*script_out, timeout); + + *script_err = procnew->err; + if (!*script_err) + return APR_EBADF; +- apr_file_pipe_timeout_set(*script_err, r->server->timeout); ++ apr_file_pipe_timeout_set(*script_err, timeout); + } + } + } +@@ -536,209 +563,12 @@ static apr_status_t default_build_command(const char **cmd, const char ***argv, + return APR_SUCCESS; + } + +-static void discard_script_output(apr_bucket_brigade *bb) +-{ +- apr_bucket *e; +- const char *buf; +- apr_size_t len; +- +- for (e = APR_BRIGADE_FIRST(bb); +- e != APR_BRIGADE_SENTINEL(bb) && !APR_BUCKET_IS_EOS(e); +- e = APR_BRIGADE_FIRST(bb)) +- { +- if (apr_bucket_read(e, &buf, &len, APR_BLOCK_READ)) { +- break; +- } +- apr_bucket_delete(e); +- } +-} +- + #if APR_FILES_AS_SOCKETS +- +-/* A CGI bucket type is needed to catch any output to stderr from the +- * script; see PR 22030. */ +-static const apr_bucket_type_t bucket_type_cgi; +- +-struct cgi_bucket_data { +- apr_pollset_t *pollset; +- request_rec *r; +-}; +- +-/* Create a CGI bucket using pipes from script stdout 'out' +- * and stderr 'err', for request 'r'. */ +-static apr_bucket *cgi_bucket_create(request_rec *r, +- apr_file_t *out, apr_file_t *err, +- apr_bucket_alloc_t *list) +-{ +- apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); +- apr_status_t rv; +- apr_pollfd_t fd; +- struct cgi_bucket_data *data = apr_palloc(r->pool, sizeof *data); +- +- APR_BUCKET_INIT(b); +- b->free = apr_bucket_free; +- b->list = list; +- b->type = &bucket_type_cgi; +- b->length = (apr_size_t)(-1); +- b->start = -1; +- +- /* Create the pollset */ +- rv = apr_pollset_create(&data->pollset, 2, r->pool, 0); +- if (rv != APR_SUCCESS) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01217) +- "apr_pollset_create(); check system or user limits"); +- return NULL; +- } +- +- fd.desc_type = APR_POLL_FILE; +- fd.reqevents = APR_POLLIN; +- fd.p = r->pool; +- fd.desc.f = out; /* script's stdout */ +- fd.client_data = (void *)1; +- rv = apr_pollset_add(data->pollset, &fd); +- if (rv != APR_SUCCESS) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01218) +- "apr_pollset_add(); check system or user limits"); +- return NULL; +- } +- +- fd.desc.f = err; /* script's stderr */ +- fd.client_data = (void *)2; +- rv = apr_pollset_add(data->pollset, &fd); +- if (rv != APR_SUCCESS) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01219) +- "apr_pollset_add(); check system or user limits"); +- return NULL; +- } +- +- data->r = r; +- b->data = data; +- return b; +-} +- +-/* Create a duplicate CGI bucket using given bucket data */ +-static apr_bucket *cgi_bucket_dup(struct cgi_bucket_data *data, +- apr_bucket_alloc_t *list) +-{ +- apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); +- APR_BUCKET_INIT(b); +- b->free = apr_bucket_free; +- b->list = list; +- b->type = &bucket_type_cgi; +- b->length = (apr_size_t)(-1); +- b->start = -1; +- b->data = data; +- return b; +-} +- +-/* Handle stdout from CGI child. Duplicate of logic from the _read +- * method of the real APR pipe bucket implementation. */ +-static apr_status_t cgi_read_stdout(apr_bucket *a, apr_file_t *out, +- const char **str, apr_size_t *len) +-{ +- char *buf; +- apr_status_t rv; +- +- *str = NULL; +- *len = APR_BUCKET_BUFF_SIZE; +- buf = apr_bucket_alloc(*len, a->list); /* XXX: check for failure? */ +- +- rv = apr_file_read(out, buf, len); +- +- if (rv != APR_SUCCESS && rv != APR_EOF) { +- apr_bucket_free(buf); +- return rv; +- } +- +- if (*len > 0) { +- struct cgi_bucket_data *data = a->data; +- apr_bucket_heap *h; +- +- /* Change the current bucket to refer to what we read */ +- a = apr_bucket_heap_make(a, buf, *len, apr_bucket_free); +- h = a->data; +- h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */ +- *str = buf; +- APR_BUCKET_INSERT_AFTER(a, cgi_bucket_dup(data, a->list)); +- } +- else { +- apr_bucket_free(buf); +- a = apr_bucket_immortal_make(a, "", 0); +- *str = a->data; +- } +- return rv; +-} +- +-/* Read method of CGI bucket: polls on stderr and stdout of the child, +- * sending any stderr output immediately away to the error log. */ +-static apr_status_t cgi_bucket_read(apr_bucket *b, const char **str, +- apr_size_t *len, apr_read_type_e block) +-{ +- struct cgi_bucket_data *data = b->data; +- apr_interval_time_t timeout; +- apr_status_t rv; +- int gotdata = 0; +- +- timeout = block == APR_NONBLOCK_READ ? 0 : data->r->server->timeout; +- +- do { +- const apr_pollfd_t *results; +- apr_int32_t num; +- +- rv = apr_pollset_poll(data->pollset, timeout, &num, &results); +- if (APR_STATUS_IS_TIMEUP(rv)) { +- if (timeout) { +- ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, data->r, APLOGNO(01220) +- "Timeout waiting for output from CGI script %s", +- data->r->filename); +- return rv; +- } +- else { +- return APR_EAGAIN; +- } +- } +- else if (APR_STATUS_IS_EINTR(rv)) { +- continue; +- } +- else if (rv != APR_SUCCESS) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, data->r, APLOGNO(01221) +- "poll failed waiting for CGI child"); +- return rv; +- } +- +- for (; num; num--, results++) { +- if (results[0].client_data == (void *)1) { +- /* stdout */ +- rv = cgi_read_stdout(b, results[0].desc.f, str, len); +- if (APR_STATUS_IS_EOF(rv)) { +- rv = APR_SUCCESS; +- } +- gotdata = 1; +- } else { +- /* stderr */ +- apr_status_t rv2 = log_script_err(data->r, results[0].desc.f); +- if (APR_STATUS_IS_EOF(rv2)) { +- apr_pollset_remove(data->pollset, &results[0]); +- } +- } +- } +- +- } while (!gotdata); +- +- return rv; +-} +- +-static const apr_bucket_type_t bucket_type_cgi = { +- "CGI", 5, APR_BUCKET_DATA, +- apr_bucket_destroy_noop, +- cgi_bucket_read, +- apr_bucket_setaside_notimpl, +- apr_bucket_split_notimpl, +- apr_bucket_copy_notimpl +-}; +- ++#define WANT_CGI_BUCKET + #endif + ++#include "cgi_common.h" ++ + static int cgi_handler(request_rec *r) + { + int nph; +@@ -757,6 +587,8 @@ static int cgi_handler(request_rec *r) + apr_status_t rv; + cgi_exec_info_t e_info; + conn_rec *c; ++ cgi_dirconf *dc = ap_get_module_config(r->per_dir_config, &cgi_module); ++ apr_interval_time_t timeout = dc->timeout > 0 ? dc->timeout : r->server->timeout; + + if (strcmp(r->handler, CGI_MAGIC_TYPE) && strcmp(r->handler, "cgi-script")) { + return DECLINED; +@@ -916,10 +748,7 @@ static int cgi_handler(request_rec *r) + AP_DEBUG_ASSERT(script_in != NULL); + + #if APR_FILES_AS_SOCKETS +- apr_file_pipe_timeout_set(script_in, 0); +- apr_file_pipe_timeout_set(script_err, 0); +- +- b = cgi_bucket_create(r, script_in, script_err, c->bucket_alloc); ++ b = cgi_bucket_create(r, dc->timeout, script_in, script_err, c->bucket_alloc); + if (b == NULL) + return HTTP_INTERNAL_SERVER_ERROR; + #else +@@ -929,111 +758,7 @@ static int cgi_handler(request_rec *r) + b = apr_bucket_eos_create(c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb, b); + +- /* Handle script return... */ +- if (!nph) { +- const char *location; +- char sbuf[MAX_STRING_LEN]; +- int ret; +- +- if ((ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf, +- APLOG_MODULE_INDEX))) +- { +- ret = log_script(r, conf, ret, dbuf, sbuf, bb, script_err); +- +- /* +- * ret could be HTTP_NOT_MODIFIED in the case that the CGI script +- * does not set an explicit status and ap_meets_conditions, which +- * is called by ap_scan_script_header_err_brigade, detects that +- * the conditions of the requests are met and the response is +- * not modified. +- * In this case set r->status and return OK in order to prevent +- * running through the error processing stack as this would +- * break with mod_cache, if the conditions had been set by +- * mod_cache itself to validate a stale entity. +- * BTW: We circumvent the error processing stack anyway if the +- * CGI script set an explicit status code (whatever it is) and +- * the only possible values for ret here are: +- * +- * HTTP_NOT_MODIFIED (set by ap_meets_conditions) +- * HTTP_PRECONDITION_FAILED (set by ap_meets_conditions) +- * HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the +- * processing of the response of the CGI script, e.g broken headers +- * or a crashed CGI process). +- */ +- if (ret == HTTP_NOT_MODIFIED) { +- r->status = ret; +- return OK; +- } +- +- return ret; +- } +- +- location = apr_table_get(r->headers_out, "Location"); +- +- if (location && r->status == 200) { +- /* For a redirect whether internal or not, discard any +- * remaining stdout from the script, and log any remaining +- * stderr output, as normal. */ +- discard_script_output(bb); +- apr_brigade_destroy(bb); +- apr_file_pipe_timeout_set(script_err, r->server->timeout); +- log_script_err(r, script_err); +- } +- +- if (location && location[0] == '/' && r->status == 200) { +- /* This redirect needs to be a GET no matter what the original +- * method was. +- */ +- r->method = "GET"; +- r->method_number = M_GET; +- +- /* We already read the message body (if any), so don't allow +- * the redirected request to think it has one. We can ignore +- * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. +- */ +- apr_table_unset(r->headers_in, "Content-Length"); +- +- ap_internal_redirect_handler(location, r); +- return OK; +- } +- else if (location && r->status == 200) { +- /* XXX: Note that if a script wants to produce its own Redirect +- * body, it now has to explicitly *say* "Status: 302" +- */ +- return HTTP_MOVED_TEMPORARILY; +- } +- +- rv = ap_pass_brigade(r->output_filters, bb); +- } +- else /* nph */ { +- struct ap_filter_t *cur; +- +- /* get rid of all filters up through protocol... since we +- * haven't parsed off the headers, there is no way they can +- * work +- */ +- +- cur = r->proto_output_filters; +- while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION) { +- cur = cur->next; +- } +- r->output_filters = r->proto_output_filters = cur; +- +- rv = ap_pass_brigade(r->output_filters, bb); +- } +- +- /* don't soak up script output if errors occurred writing it +- * out... otherwise, we prolong the life of the script when the +- * connection drops or we stopped sending output for some other +- * reason */ +- if (rv == APR_SUCCESS && !r->connection->aborted) { +- apr_file_pipe_timeout_set(script_err, r->server->timeout); +- log_script_err(r, script_err); +- } +- +- apr_file_close(script_err); +- +- return OK; /* NOT r->status, even if it has changed. */ ++ return cgi_handle_response(r, nph, bb, timeout, conf, dbuf, script_err); + } + + /*============================================================================ +@@ -1268,7 +993,7 @@ static void register_hooks(apr_pool_t *p) + AP_DECLARE_MODULE(cgi) = + { + STANDARD20_MODULE_STUFF, +- NULL, /* dir config creater */ ++ create_cgi_dirconf, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + create_cgi_config, /* server config */ + merge_cgi_config, /* merge server config */ +diff --git a/modules/generators/mod_cgid.c b/modules/generators/mod_cgid.c +index 9f4282c..102d2b3 100644 +--- a/modules/generators/mod_cgid.c ++++ b/modules/generators/mod_cgid.c +@@ -342,15 +342,19 @@ static apr_status_t close_unix_socket(void *thefd) + return close(fd); + } + +-/* deal with incomplete reads and signals +- * assume you really have to read buf_size bytes +- */ +-static apr_status_t sock_read(int fd, void *vbuf, size_t buf_size) ++/* Read from the socket dealing with incomplete messages and signals. ++ * Returns 0 on success or errno on failure. Stderr fd passed as ++ * auxiliary data from other end is written to *errfd, or else stderr ++ * fileno if not present. */ ++static apr_status_t sock_readhdr(int fd, int *errfd, void *vbuf, size_t buf_size) + { +- char *buf = vbuf; + int rc; ++#ifndef HAVE_CGID_FDPASSING ++ char *buf = vbuf; + size_t bytes_read = 0; + ++ if (errfd) *errfd = 0; ++ + do { + do { + rc = read(fd, buf + bytes_read, buf_size - bytes_read); +@@ -365,9 +369,60 @@ static apr_status_t sock_read(int fd, void *vbuf, size_t buf_size) + } + } while (bytes_read < buf_size); + ++ ++#else /* with FD passing */ ++ struct msghdr msg = {0}; ++ struct iovec vec = {vbuf, buf_size}; ++ struct cmsghdr *cmsg; ++ union { /* union to ensure alignment */ ++ struct cmsghdr cm; ++ char buf[CMSG_SPACE(sizeof(int))]; ++ } u; ++ ++ msg.msg_iov = &vec; ++ msg.msg_iovlen = 1; ++ ++ if (errfd) { ++ msg.msg_control = u.buf; ++ msg.msg_controllen = sizeof(u.buf); ++ *errfd = 0; ++ } ++ ++ /* use MSG_WAITALL to skip loop on truncated reads */ ++ do { ++ rc = recvmsg(fd, &msg, MSG_WAITALL); ++ } while (rc < 0 && errno == EINTR); ++ ++ if (rc == 0) { ++ return ECONNRESET; ++ } ++ else if (rc < 0) { ++ return errno; ++ } ++ else if (rc != buf_size) { ++ /* MSG_WAITALL should ensure the recvmsg blocks until the ++ * entire length is read, but let's be paranoid. */ ++ return APR_INCOMPLETE; ++ } ++ ++ if (errfd ++ && (cmsg = CMSG_FIRSTHDR(&msg)) != NULL ++ && cmsg->cmsg_len == CMSG_LEN(sizeof(*errfd)) ++ && cmsg->cmsg_level == SOL_SOCKET ++ && cmsg->cmsg_type == SCM_RIGHTS) { ++ *errfd = *((int *) CMSG_DATA(cmsg)); ++ } ++#endif ++ + return APR_SUCCESS; + } + ++/* As sock_readhdr but without auxiliary fd passing. */ ++static apr_status_t sock_read(int fd, void *vbuf, size_t buf_size) ++{ ++ return sock_readhdr(fd, NULL, vbuf, buf_size); ++} ++ + /* deal with signals + */ + static apr_status_t sock_write(int fd, const void *buf, size_t buf_size) +@@ -384,7 +439,7 @@ static apr_status_t sock_write(int fd, const void *buf, size_t buf_size) + return APR_SUCCESS; + } + +-static apr_status_t sock_writev(int fd, request_rec *r, int count, ...) ++static apr_status_t sock_writev(int fd, int auxfd, request_rec *r, int count, ...) + { + va_list ap; + int rc; +@@ -399,9 +454,39 @@ static apr_status_t sock_writev(int fd, request_rec *r, int count, ...) + } + va_end(ap); + ++#ifndef HAVE_CGID_FDPASSING + do { + rc = writev(fd, vec, count); + } while (rc < 0 && errno == EINTR); ++#else ++ { ++ struct msghdr msg = { 0 }; ++ struct cmsghdr *cmsg; ++ union { /* union for alignment */ ++ char buf[CMSG_SPACE(sizeof(int))]; ++ struct cmsghdr align; ++ } u; ++ ++ msg.msg_iov = vec; ++ msg.msg_iovlen = count; ++ ++ if (auxfd) { ++ msg.msg_control = u.buf; ++ msg.msg_controllen = sizeof(u.buf); ++ ++ cmsg = CMSG_FIRSTHDR(&msg); ++ cmsg->cmsg_level = SOL_SOCKET; ++ cmsg->cmsg_type = SCM_RIGHTS; ++ cmsg->cmsg_len = CMSG_LEN(sizeof(int)); ++ *((int *) CMSG_DATA(cmsg)) = auxfd; ++ } ++ ++ do { ++ rc = sendmsg(fd, &msg, 0); ++ } while (rc < 0 && errno == EINTR); ++ } ++#endif ++ + if (rc < 0) { + return errno; + } +@@ -410,7 +495,7 @@ static apr_status_t sock_writev(int fd, request_rec *r, int count, ...) + } + + static apr_status_t get_req(int fd, request_rec *r, char **argv0, char ***env, +- cgid_req_t *req) ++ int *errfd, cgid_req_t *req) + { + int i; + char **environ; +@@ -421,7 +506,7 @@ static apr_status_t get_req(int fd, request_rec *r, char **argv0, char ***env, + r->server = apr_pcalloc(r->pool, sizeof(server_rec)); + + /* read the request header */ +- stat = sock_read(fd, req, sizeof(*req)); ++ stat = sock_readhdr(fd, errfd, req, sizeof(*req)); + if (stat != APR_SUCCESS) { + return stat; + } +@@ -479,14 +564,15 @@ static apr_status_t get_req(int fd, request_rec *r, char **argv0, char ***env, + return APR_SUCCESS; + } + +-static apr_status_t send_req(int fd, request_rec *r, char *argv0, char **env, +- int req_type) ++static apr_status_t send_req(int fd, apr_file_t *errpipe, request_rec *r, ++ char *argv0, char **env, int req_type) + { + int i; + cgid_req_t req = {0}; + apr_status_t stat; + ap_unix_identity_t * ugid = ap_run_get_suexec_identity(r); + core_dir_config *core_conf = ap_get_core_module_config(r->per_dir_config); ++ int errfd; + + + if (ugid == NULL) { +@@ -507,16 +593,21 @@ static apr_status_t send_req(int fd, request_rec *r, char *argv0, char **env, + req.args_len = r->args ? strlen(r->args) : 0; + req.loglevel = r->server->log.level; + ++ if (errpipe) ++ apr_os_file_get(&errfd, errpipe); ++ else ++ errfd = 0; ++ + /* Write the request header */ + if (req.args_len) { +- stat = sock_writev(fd, r, 5, ++ stat = sock_writev(fd, errfd, r, 5, + &req, sizeof(req), + r->filename, req.filename_len, + argv0, req.argv0_len, + r->uri, req.uri_len, + r->args, req.args_len); + } else { +- stat = sock_writev(fd, r, 4, ++ stat = sock_writev(fd, errfd, r, 4, + &req, sizeof(req), + r->filename, req.filename_len, + argv0, req.argv0_len, +@@ -531,7 +622,7 @@ static apr_status_t send_req(int fd, request_rec *r, char *argv0, char **env, + for (i = 0; i < req.env_count; i++) { + apr_size_t curlen = strlen(env[i]); + +- if ((stat = sock_writev(fd, r, 2, &curlen, sizeof(curlen), ++ if ((stat = sock_writev(fd, 0, r, 2, &curlen, sizeof(curlen), + env[i], curlen)) != APR_SUCCESS) { + return stat; + } +@@ -582,20 +673,34 @@ static void daemon_signal_handler(int sig) + } + } + ++/* Callback executed in the forked child process if exec of the CGI ++ * script fails. For the fd-passing case, output to stderr goes to ++ * the client (request handling thread) and is logged via ++ * ap_log_rerror there. For the non-fd-passing case, the "fake" ++ * request_rec passed via userdata is used to log. */ + static void cgid_child_errfn(apr_pool_t *pool, apr_status_t err, + const char *description) + { +- request_rec *r; + void *vr; + + apr_pool_userdata_get(&vr, ERRFN_USERDATA_KEY, pool); +- r = vr; +- +- /* sure we got r, but don't call ap_log_rerror() because we don't +- * have r->headers_in and possibly other storage referenced by +- * ap_log_rerror() +- */ +- ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server, APLOGNO(01241) "%s", description); ++ if (vr) { ++ request_rec *r = vr; ++ ++ /* sure we got r, but don't call ap_log_rerror() because we don't ++ * have r->headers_in and possibly other storage referenced by ++ * ap_log_rerror() ++ */ ++ ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server, APLOGNO(01241) "%s", description); ++ } ++ else { ++ const char *logstr; ++ ++ logstr = apr_psprintf(pool, APLOGNO(01241) "error spawning CGI child: %s (%pm)\n", ++ description, &err); ++ fputs(logstr, stderr); ++ fflush(stderr); ++ } + } + + static int cgid_server(void *data) +@@ -669,7 +774,7 @@ static int cgid_server(void *data) + } + + while (!daemon_should_exit) { +- int errfileno = STDERR_FILENO; ++ int errfileno; + char *argv0 = NULL; + char **env = NULL; + const char * const *argv; +@@ -709,7 +814,7 @@ static int cgid_server(void *data) + r = apr_pcalloc(ptrans, sizeof(request_rec)); + procnew = apr_pcalloc(ptrans, sizeof(*procnew)); + r->pool = ptrans; +- stat = get_req(sd2, r, &argv0, &env, &cgid_req); ++ stat = get_req(sd2, r, &argv0, &env, &errfileno, &cgid_req); + if (stat != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, stat, + main_server, APLOGNO(01248) +@@ -741,6 +846,16 @@ static int cgid_server(void *data) + continue; + } + ++ if (errfileno == 0) { ++ errfileno = STDERR_FILENO; ++ } ++ else { ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, main_server, ++ "using passed fd %d as stderr", errfileno); ++ /* Limit the received fd lifetime to pool lifetime */ ++ apr_pool_cleanup_register(ptrans, (void *)((long)errfileno), ++ close_unix_socket, close_unix_socket); ++ } + apr_os_file_put(&r->server->error_log, &errfileno, 0, r->pool); + apr_os_file_put(&inout, &sd2, 0, r->pool); + +@@ -800,7 +915,10 @@ static int cgid_server(void *data) + close(sd2); + } + else { +- apr_pool_userdata_set(r, ERRFN_USERDATA_KEY, apr_pool_cleanup_null, ptrans); ++ if (errfileno == STDERR_FILENO) { ++ /* Used by cgid_child_errfn without fd-passing. */ ++ apr_pool_userdata_set(r, ERRFN_USERDATA_KEY, apr_pool_cleanup_null, ptrans); ++ } + + argv = (const char * const *)create_argv(r->pool, NULL, NULL, NULL, argv0, r->args); + +@@ -1099,6 +1217,33 @@ static int log_scripterror(request_rec *r, cgid_server_conf * conf, int ret, + return ret; + } + ++/* Soak up stderr from a script and redirect it to the error log. ++ * TODO: log_scripterror() and this could move to cgi_common.h. */ ++static apr_status_t log_script_err(request_rec *r, apr_file_t *script_err) ++{ ++ char argsbuffer[HUGE_STRING_LEN]; ++ char *newline; ++ apr_status_t rv; ++ cgid_server_conf *conf = ap_get_module_config(r->server->module_config, &cgid_module); ++ ++ while ((rv = apr_file_gets(argsbuffer, HUGE_STRING_LEN, ++ script_err)) == APR_SUCCESS) { ++ ++ newline = strchr(argsbuffer, '\n'); ++ if (newline) { ++ char *prev = newline - 1; ++ if (prev >= argsbuffer && *prev == '\r') { ++ newline = prev; ++ } ++ ++ *newline = '\0'; ++ } ++ log_scripterror(r, conf, r->status, 0, argsbuffer); ++ } ++ ++ return rv; ++} ++ + static int log_script(request_rec *r, cgid_server_conf * conf, int ret, + char *dbuf, const char *sbuf, apr_bucket_brigade *bb, + apr_file_t *script_err) +@@ -1204,6 +1349,13 @@ static int log_script(request_rec *r, cgid_server_conf * conf, int ret, + return ret; + } + ++/* Pull in CGI bucket implementation. */ ++#define cgi_server_conf cgid_server_conf ++#ifdef HAVE_CGID_FDPASSING ++#define WANT_CGI_BUCKET ++#endif ++#include "cgi_common.h" ++ + static int connect_to_daemon(int *sdptr, request_rec *r, + cgid_server_conf *conf) + { +@@ -1270,23 +1422,6 @@ static int connect_to_daemon(int *sdptr, request_rec *r, + return OK; + } + +-static void discard_script_output(apr_bucket_brigade *bb) +-{ +- apr_bucket *e; +- const char *buf; +- apr_size_t len; +- +- for (e = APR_BRIGADE_FIRST(bb); +- e != APR_BRIGADE_SENTINEL(bb) && !APR_BUCKET_IS_EOS(e); +- e = APR_BRIGADE_FIRST(bb)) +- { +- if (apr_bucket_read(e, &buf, &len, APR_BLOCK_READ)) { +- break; +- } +- apr_bucket_delete(e); +- } +-} +- + /**************************************************************** + * + * Actual cgid handling... +@@ -1391,6 +1526,7 @@ static apr_status_t cleanup_script(void *vptr) + + static int cgid_handler(request_rec *r) + { ++ conn_rec *c = r->connection; + int retval, nph, dbpos; + char *argv0, *dbuf; + apr_bucket_brigade *bb; +@@ -1400,10 +1536,11 @@ static int cgid_handler(request_rec *r) + int seen_eos, child_stopped_reading; + int sd; + char **env; +- apr_file_t *tempsock; ++ apr_file_t *tempsock, *script_err, *errpipe_out; + struct cleanup_script_info *info; + apr_status_t rv; + cgid_dirconf *dc; ++ apr_interval_time_t timeout; + + if (strcmp(r->handler, CGI_MAGIC_TYPE) && strcmp(r->handler, "cgi-script")) { + return DECLINED; +@@ -1412,7 +1549,7 @@ static int cgid_handler(request_rec *r) + conf = ap_get_module_config(r->server->module_config, &cgid_module); + dc = ap_get_module_config(r->per_dir_config, &cgid_module); + +- ++ timeout = dc->timeout > 0 ? dc->timeout : r->server->timeout; + is_included = !strcmp(r->protocol, "INCLUDED"); + + if ((argv0 = strrchr(r->filename, '/')) != NULL) { +@@ -1465,6 +1602,17 @@ static int cgid_handler(request_rec *r) + } + */ + ++#ifdef HAVE_CGID_FDPASSING ++ rv = apr_file_pipe_create(&script_err, &errpipe_out, r->pool); ++ if (rv) { ++ return log_scripterror(r, conf, HTTP_SERVICE_UNAVAILABLE, rv, APLOGNO(10176) ++ "could not create pipe for stderr"); ++ } ++#else ++ script_err = NULL; ++ errpipe_out = NULL; ++#endif ++ + /* + * httpd core function used to add common environment variables like + * DOCUMENT_ROOT. +@@ -1477,12 +1625,16 @@ static int cgid_handler(request_rec *r) + return retval; + } + +- rv = send_req(sd, r, argv0, env, CGI_REQ); ++ rv = send_req(sd, errpipe_out, r, argv0, env, CGI_REQ); + if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01268) + "write to cgi daemon process"); + } + ++ /* The write-end of the pipe is only used by the server, so close ++ * it here. */ ++ if (errpipe_out) apr_file_close(errpipe_out); ++ + info = apr_palloc(r->pool, sizeof(struct cleanup_script_info)); + info->conf = conf; + info->r = r; +@@ -1504,12 +1656,7 @@ static int cgid_handler(request_rec *r) + */ + + apr_os_pipe_put_ex(&tempsock, &sd, 1, r->pool); +- if (dc->timeout > 0) { +- apr_file_pipe_timeout_set(tempsock, dc->timeout); +- } +- else { +- apr_file_pipe_timeout_set(tempsock, r->server->timeout); +- } ++ apr_file_pipe_timeout_set(tempsock, timeout); + apr_pool_cleanup_kill(r->pool, (void *)((long)sd), close_unix_socket); + + /* Transfer any put/post args, CERN style... +@@ -1601,114 +1748,19 @@ static int cgid_handler(request_rec *r) + */ + shutdown(sd, 1); + +- /* Handle script return... */ +- if (!nph) { +- conn_rec *c = r->connection; +- const char *location; +- char sbuf[MAX_STRING_LEN]; +- int ret; +- +- bb = apr_brigade_create(r->pool, c->bucket_alloc); +- b = apr_bucket_pipe_create(tempsock, c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(bb, b); +- b = apr_bucket_eos_create(c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(bb, b); +- +- if ((ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf, +- APLOG_MODULE_INDEX))) +- { +- ret = log_script(r, conf, ret, dbuf, sbuf, bb, NULL); +- +- /* +- * ret could be HTTP_NOT_MODIFIED in the case that the CGI script +- * does not set an explicit status and ap_meets_conditions, which +- * is called by ap_scan_script_header_err_brigade, detects that +- * the conditions of the requests are met and the response is +- * not modified. +- * In this case set r->status and return OK in order to prevent +- * running through the error processing stack as this would +- * break with mod_cache, if the conditions had been set by +- * mod_cache itself to validate a stale entity. +- * BTW: We circumvent the error processing stack anyway if the +- * CGI script set an explicit status code (whatever it is) and +- * the only possible values for ret here are: +- * +- * HTTP_NOT_MODIFIED (set by ap_meets_conditions) +- * HTTP_PRECONDITION_FAILED (set by ap_meets_conditions) +- * HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the +- * processing of the response of the CGI script, e.g broken headers +- * or a crashed CGI process). +- */ +- if (ret == HTTP_NOT_MODIFIED) { +- r->status = ret; +- return OK; +- } +- +- return ret; +- } +- +- location = apr_table_get(r->headers_out, "Location"); +- +- if (location && location[0] == '/' && r->status == 200) { +- +- /* Soak up all the script output */ +- discard_script_output(bb); +- apr_brigade_destroy(bb); +- /* This redirect needs to be a GET no matter what the original +- * method was. +- */ +- r->method = "GET"; +- r->method_number = M_GET; +- +- /* We already read the message body (if any), so don't allow +- * the redirected request to think it has one. We can ignore +- * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. +- */ +- apr_table_unset(r->headers_in, "Content-Length"); +- +- ap_internal_redirect_handler(location, r); +- return OK; +- } +- else if (location && r->status == 200) { +- /* XXX: Note that if a script wants to produce its own Redirect +- * body, it now has to explicitly *say* "Status: 302" +- */ +- discard_script_output(bb); +- apr_brigade_destroy(bb); +- return HTTP_MOVED_TEMPORARILY; +- } +- +- rv = ap_pass_brigade(r->output_filters, bb); +- if (rv != APR_SUCCESS) { +- ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r, +- "Failed to flush CGI output to client"); +- } +- } +- +- if (nph) { +- conn_rec *c = r->connection; +- struct ap_filter_t *cur; +- +- /* get rid of all filters up through protocol... since we +- * haven't parsed off the headers, there is no way they can +- * work +- */ +- +- cur = r->proto_output_filters; +- while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION) { +- cur = cur->next; +- } +- r->output_filters = r->proto_output_filters = cur; +- +- bb = apr_brigade_create(r->pool, c->bucket_alloc); +- b = apr_bucket_pipe_create(tempsock, c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(bb, b); +- b = apr_bucket_eos_create(c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(bb, b); +- ap_pass_brigade(r->output_filters, bb); +- } ++ bb = apr_brigade_create(r->pool, c->bucket_alloc); ++#ifdef HAVE_CGID_FDPASSING ++ b = cgi_bucket_create(r, dc->timeout, tempsock, script_err, c->bucket_alloc); ++ if (b == NULL) ++ return HTTP_INTERNAL_SERVER_ERROR; /* should call log_scripterror() w/ _UNAVAILABLE? */ ++#else ++ b = apr_bucket_pipe_create(tempsock, c->bucket_alloc); ++#endif ++ APR_BRIGADE_INSERT_TAIL(bb, b); ++ b = apr_bucket_eos_create(c->bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(bb, b); + +- return OK; /* NOT r->status, even if it has changed. */ ++ return cgi_handle_response(r, nph, bb, timeout, conf, dbuf, script_err); + } + + +@@ -1825,7 +1877,7 @@ static int include_cmd(include_ctx_t *ctx, ap_filter_t *f, + return retval; + } + +- send_req(sd, r, command, env, SSI_REQ); ++ send_req(sd, NULL, r, command, env, SSI_REQ); + + info = apr_palloc(r->pool, sizeof(struct cleanup_script_info)); + info->conf = conf;