]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
* modules/http/chunk_filter.c (ap_http_chunk_filter): For a brigade
authorJoe Orton <jorton@apache.org>
Wed, 20 Dec 2023 15:56:15 +0000 (15:56 +0000)
committerJoe Orton <jorton@apache.org>
Wed, 20 Dec 2023 15:56:15 +0000 (15:56 +0000)
  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 [new file with mode: 0644]
modules/http/chunk_filter.c

diff --git a/changes-entries/flushing-chunks.txt b/changes-entries/flushing-chunks.txt
new file mode 100644 (file)
index 0000000..7e9519f
--- /dev/null
@@ -0,0 +1,2 @@
+  *) http/1.1: For a chunked response body, ensure the last-chunk
+     terminator is flushed if necessary. [Joe Orton]
index f44543a7657fc2730aa98fa51deb5fb0d8604445..1fa3fa935205a558483af6f09eb81ea3915cf49f 100644 (file)
@@ -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);
             }