From b022e3b52344b687c25875b0a7d6c1ee26f8e5fa Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Sep 13 2017 13:21:17 +0000 Subject: add new content-length filter (upstream PR 61222) --- diff --git a/.gitignore b/.gitignore index 19a3666..e364382 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,7 @@ x86_64 /httpd-2.2.21.tar.bz2 /clog /httpd-2.2.22.tar.bz2 -/httpd-2.4.? +/httpd-2.4.??/ /httpd-2.4.2.tar.bz2 /httpd-2.4.3.tar.bz2 /httpd-2.4.4.tar.bz2 diff --git a/httpd-2.4.27-r1808230.patch b/httpd-2.4.27-r1808230.patch new file mode 100644 index 0000000..e4062ea --- /dev/null +++ b/httpd-2.4.27-r1808230.patch @@ -0,0 +1,131 @@ +# ./pullrev.sh 1808230 +http://svn.apache.org/viewvc?view=revision&revision=1808230 + +--- httpd-2.4.27/server/protocol.c ++++ httpd-2.4.27/server/protocol.c +@@ -1708,62 +1708,88 @@ + ctx->tmpbb = apr_brigade_create(r->pool, r->connection->bucket_alloc); + } + +- /* Loop through this set of buckets to compute their length +- */ ++ /* Loop through the brigade to count the length. To avoid ++ * arbitrary memory consumption with morphing bucket types, this ++ * loop will stop and pass on the brigade when necessary. */ + e = APR_BRIGADE_FIRST(b); + while (e != APR_BRIGADE_SENTINEL(b)) { ++ apr_status_t rv; ++ + if (APR_BUCKET_IS_EOS(e)) { + eos = 1; + break; + } +- if (e->length == (apr_size_t)-1) { ++ /* For a flush bucket, fall through to pass the brigade and ++ * flush now. */ ++ else if (APR_BUCKET_IS_FLUSH(e)) { ++ e = APR_BUCKET_NEXT(e); ++ } ++ /* For metadata bucket types other than FLUSH, loop. */ ++ else if (APR_BUCKET_IS_METADATA(e)) { ++ e = APR_BUCKET_NEXT(e); ++ continue; ++ } ++ /* For determinate length data buckets, count the length and ++ * continue. */ ++ else if (e->length != (apr_size_t)-1) { ++ r->bytes_sent += e->length; ++ e = APR_BUCKET_NEXT(e); ++ continue; ++ } ++ /* For indeterminate length data buckets, perform one read. */ ++ else /* e->length == (apr_size_t)-1 */ { + apr_size_t len; + const char *ignored; +- apr_status_t rv; +- +- /* This is probably a pipe bucket. Send everything +- * prior to this, and then read the data for this bucket. +- */ ++ + rv = apr_bucket_read(e, &ignored, &len, eblock); ++ if ((rv != APR_SUCCESS) && !APR_STATUS_IS_EAGAIN(rv)) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00574) ++ "ap_content_length_filter: " ++ "apr_bucket_read() failed"); ++ return rv; ++ } + if (rv == APR_SUCCESS) { +- /* Attempt a nonblocking read next time through */ + eblock = APR_NONBLOCK_READ; ++ e = APR_BUCKET_NEXT(e); + r->bytes_sent += len; + } + else if (APR_STATUS_IS_EAGAIN(rv)) { +- /* Output everything prior to this bucket, and then +- * do a blocking read on the next batch. +- */ +- if (e != APR_BRIGADE_FIRST(b)) { +- apr_bucket *flush; +- apr_brigade_split_ex(b, e, ctx->tmpbb); +- flush = apr_bucket_flush_create(r->connection->bucket_alloc); ++ apr_bucket *flush; + +- APR_BRIGADE_INSERT_TAIL(b, flush); +- rv = ap_pass_brigade(f->next, b); +- if (rv != APR_SUCCESS || f->c->aborted) { +- return rv; +- } +- apr_brigade_cleanup(b); +- APR_BRIGADE_CONCAT(b, ctx->tmpbb); +- e = APR_BRIGADE_FIRST(b); ++ /* Next read must block. */ ++ eblock = APR_BLOCK_READ; + +- ctx->data_sent = 1; +- } +- eblock = APR_BLOCK_READ; +- continue; ++ /* Ensure the last bucket to pass down is a flush if ++ * the next read will block. */ ++ flush = apr_bucket_flush_create(f->c->bucket_alloc); ++ APR_BUCKET_INSERT_BEFORE(e, flush); + } +- else { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00574) +- "ap_content_length_filter: " +- "apr_bucket_read() failed"); +- return rv; +- } + } +- else { +- r->bytes_sent += e->length; ++ ++ /* Optimization: if the next bucket is EOS (directly after a ++ * bucket morphed to the heap, or a flush), short-cut to ++ * handle EOS straight away - allowing C-L to be determined ++ * for content which is already entirely in memory. */ ++ if (e != APR_BRIGADE_SENTINEL(b) && APR_BUCKET_IS_EOS(e)) { ++ continue; + } +- e = APR_BUCKET_NEXT(e); ++ ++ /* On reaching here, pass on everything in the brigade up to ++ * this point. */ ++ apr_brigade_split_ex(b, e, ctx->tmpbb); ++ ++ rv = ap_pass_brigade(f->next, b); ++ if (rv != APR_SUCCESS) { ++ return rv; ++ } ++ else if (f->c->aborted) { ++ return APR_ECONNABORTED; ++ } ++ apr_brigade_cleanup(b); ++ APR_BRIGADE_CONCAT(b, ctx->tmpbb); ++ e = APR_BRIGADE_FIRST(b); ++ ++ ctx->data_sent = 1; + } + + /* If we've now seen the entire response and it's otherwise diff --git a/httpd.spec b/httpd.spec index 0e25a2c..01beaf2 100644 --- a/httpd.spec +++ b/httpd.spec @@ -13,7 +13,7 @@ Summary: Apache HTTP Server Name: httpd Version: 2.4.27 -Release: 6%{?dist} +Release: 7%{?dist} URL: https://httpd.apache.org/ Source0: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2 Source1: index.html @@ -72,6 +72,7 @@ Patch56: httpd-2.4.4-mod_unique_id.patch Patch57: httpd-2.4.10-sigint.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1397243 Patch58: httpd-2.4.25-r1738878.patch +Patch59: httpd-2.4.27-r1808230.patch # Security fixes License: ASL 2.0 @@ -218,6 +219,7 @@ interface for storing and accessing per-user session data. %patch56 -p1 -b .uniqueid %patch57 -p1 -b .sigint %patch58 -p1 -b .r1738878 +%patch59 -p1 -b .r1808230 # Patch in the vendor string sed -i '/^#define PLATFORM/s/Unix/%{vstring}/' os/unix/os.h @@ -703,6 +705,9 @@ rm -rf $RPM_BUILD_ROOT %{_rpmconfigdir}/macros.d/macros.httpd %changelog +* Wed Sep 13 2017 Joe Orton - 2.4.27-7 +- add new content-length filter (upstream PR 61222) + * Wed Aug 02 2017 Fedora Release Engineering - 2.4.27-6 - Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild diff --git a/pullrev.sh b/pullrev.sh index d106968..c366613 100755 --- a/pullrev.sh +++ b/pullrev.sh @@ -6,8 +6,8 @@ if [ $# -lt 1 ]; then fi repo="https://svn.apache.org/repos/asf/httpd/httpd/trunk" -repo="https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x" -ver=2.4.26 +#repo="https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x" +ver=2.4.27 prefix="httpd-${ver}" suffix="r$1${2:++}" fn="${prefix}-${suffix}.patch"