From b5b2ca3f3e6e95257c6d2a31278bf1f58e83c1bb Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Wed, 20 Dec 2023 15:56:15 +0000 Subject: [PATCH] * modules/http/chunk_filter.c (ap_http_chunk_filter): For a brigade containing [FLUSH EOS], insert the last-chunk terminator before the FLUSH rather than between the FLUSH and the EOS. Github: closes #400 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1914804 13f79535-47bb-0310-9956-ffa450edef68 --- changes-entries/flushing-chunks.txt | 2 ++ modules/http/chunk_filter.c | 24 ++++++++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 changes-entries/flushing-chunks.txt diff --git a/changes-entries/flushing-chunks.txt b/changes-entries/flushing-chunks.txt new file mode 100644 index 00000000000..7e9519f1184 --- /dev/null +++ b/changes-entries/flushing-chunks.txt @@ -0,0 +1,2 @@ + *) http/1.1: For a chunked response body, ensure the last-chunk + terminator is flushed if necessary. [Joe Orton] diff --git a/modules/http/chunk_filter.c b/modules/http/chunk_filter.c index f44543a7657..1fa3fa93520 100644 --- a/modules/http/chunk_filter.c +++ b/modules/http/chunk_filter.c @@ -64,7 +64,7 @@ apr_status_t ap_http_chunk_filter(ap_filter_t *f, apr_bucket_brigade *b) for (more = tmp = NULL; b; b = more, more = NULL) { apr_off_t bytes = 0; - apr_bucket *eos = NULL; + apr_bucket *eos = NULL; /* EOS bucket, or FLUSH preceding EOS */ apr_bucket *flush = NULL; /* XXX: chunk_hdr must remain at this scope since it is used in a * transient bucket. @@ -99,8 +99,20 @@ apr_status_t ap_http_chunk_filter(ap_filter_t *f, apr_bucket_brigade *b) } if (APR_BUCKET_IS_FLUSH(e)) { flush = e; + + /* Special case to catch common brigade ending of + * [FLUSH] [EOS] - insert the last_chunk before + * the FLUSH rather than between the FLUSH and the + * EOS. */ if (e != APR_BRIGADE_LAST(b)) { - more = apr_brigade_split_ex(b, APR_BUCKET_NEXT(e), tmp); + if (APR_BUCKET_IS_EOS(APR_BUCKET_NEXT(e))) { + eos = e; + /* anything after EOS is dropped, no need + * to split. */ + } + else { + more = apr_brigade_split_ex(b, APR_BUCKET_NEXT(e), tmp); + } } break; } @@ -173,12 +185,12 @@ apr_status_t ap_http_chunk_filter(ap_filter_t *f, apr_bucket_brigade *b) * FLUSH bucket, or appended to the brigade */ e = apr_bucket_immortal_create(CRLF_ASCII, 2, c->bucket_alloc); - if (eos != NULL) { - APR_BUCKET_INSERT_BEFORE(eos, e); - } - else if (flush != NULL) { + if (flush != NULL) { APR_BUCKET_INSERT_BEFORE(flush, e); } + else if (eos != NULL) { + APR_BUCKET_INSERT_BEFORE(eos, e); + } else { APR_BRIGADE_INSERT_TAIL(b, e); }