]> git.kaiwu.me - haproxy.git/commitdiff
MEDIUM: htx: Add HTX_BLK_FL_EOM flag and set it on last block of the message
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 8 Jul 2026 14:46:12 +0000 (16:46 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 18 Sep 2026 15:05:18 +0000 (17:05 +0200)
HTX_BLK_FL_EOM flag was introduced to be set on the last block of an HTX
message. It must be set on the tail block when the HTX_FL_HAS_EOM is set.
Now, only the HTX API must set these flags by hand. From outside of the HTX
API, htx_set_eom() function must be used.

A BUG_ON() was added to unsure the flag is added on valid blocks. It is possible
to add it on EOH, EOT and DATA blocks only.

include/haproxy/htx-t.h
include/haproxy/htx.h
src/hlua.c
src/htx.c

index c404812539ae5bf7a41bc45aecc323b79e7cd67f..f71502952ca25217480b832c0b403e0567c95c09 100644 (file)
@@ -215,6 +215,7 @@ enum htx_blk_type {
 };
 
 #define HTX_BLK_FL_NONE 0x00 /* For init purpose */
+#define HTX_BLK_FL_EOM  0x01 /* flag marking the end of the message */
 
 /* One HTX block descriptor */
 struct htx_blk {
index f16737aed60f2e7160e8ba2e617d18ddac90e1d2..0245653adcaa939211db45956ee8f58598d214b5 100644 (file)
@@ -841,11 +841,18 @@ static inline int htx_expect_more(const struct htx *htx)
  */
 static inline int htx_set_eom(struct htx *htx)
 {
+       struct htx_blk *blk;
+
        if (htx_is_empty(htx)) {
                if (!htx_add_endof(htx, HTX_BLK_EOT))
                        return 0;
        }
 
+       blk = ASSUME_NONNULL(htx_get_tail_blk(htx));
+       BUG_ON(htx_get_blk_type(blk) != HTX_BLK_EOH &&
+              htx_get_blk_type(blk) != HTX_BLK_EOT &&
+              htx_get_blk_type(blk) != HTX_BLK_DATA);
+       blk->flags |= HTX_BLK_FL_EOM;
        htx->flags |= HTX_FL_HAS_EOM;
        return 1;
 }
@@ -870,18 +877,27 @@ static inline int htx_copy_msg(struct htx *htx, const struct buffer *msg)
        return htx_append_msg(htx, htx_msg);
 }
 
-/* Remove all blocks except headers. Trailers will also be removed too. */
+/* Remove all blocks except headers. Trailers will also be removed too.  The EOM
+ * flag, if set on the payload part, it is then reinserted. It means a EOT black
+ * could be added if the message only contains payload.
+ */
 static inline void htx_skip_msg_payload(struct htx *htx)
 {
        struct htx_blk *blk = htx_get_first_blk(htx);
+       int eom = 0;
 
        while (blk) {
                enum htx_blk_type type = htx_get_blk_type(blk);
 
-               blk = ((type > HTX_BLK_EOH)
-                      ? htx_remove_blk(htx, blk)
-                      : htx_get_next_blk(htx, blk));
+               if (type > HTX_BLK_EOH) {
+                       eom |= !!(blk->flags & HTX_BLK_FL_EOM);
+                       blk = htx_remove_blk(htx, blk);
+               }
+               else
+                       blk = htx_get_next_blk(htx, blk);
        }
+       if (eom)
+               htx_set_eom(htx);
 }
 
 /* Returns the number of used blocks in the HTX message <htx>. Note that it is
index 094e4cd99c86c26270d49ad398c3962eb4d86098..92663a1a455ad1bb752037c9387ffb79ab7c4f8a 100644 (file)
@@ -7913,11 +7913,19 @@ __LJMP static int hlua_http_msg_unset_eom(lua_State *L)
 {
        struct http_msg *msg;
        struct htx *htx;
+       struct htx_blk *blk;
 
        MAY_LJMP(check_args(L, 1, "set_eom"));
        msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
        htx = htxbuf(&msg->chn->buf);
        htx->flags &= ~HTX_FL_HAS_EOM;
+
+       for (blk = htx_get_tail_blk(htx); blk; blk = htx_get_prev_blk(htx, blk)) {
+               if (blk->flags & HTX_BLK_FL_EOM) {
+                       blk->flags &= ~HTX_BLK_FL_EOM;
+                       break;
+               }
+       }
        return 0;
 }
 
index 3213301126ae7e0bf2e557f782dd3392c0631de9..4480ade4297df5f080ece0189e9071c2d3269cdb 100644 (file)
--- a/src/htx.c
+++ b/src/htx.c
@@ -587,7 +587,9 @@ struct htx_blk *htx_add_data_atonce(struct htx *htx, struct ist data)
        sz = htx_get_blksz(tailblk);
 
        /* Don't try to append data if the last inserted block is not of the
-        * same type */
+        * same type or if it is the end of the message */
+       if (tailblk->flags & HTX_BLK_FL_EOM)
+               goto add_new_block;
        if (htx_get_blk_type(tailblk) != HTX_BLK_DATA) {
                if (htx_get_blk_type(tailblk) > HTX_BLK_DATA)
                        flags |= HTX_FL_UNORDERED;
@@ -825,6 +827,8 @@ size_t htx_xfer(struct htx *dst, struct htx *src, size_t count, unsigned int fla
                                goto stop;
                        }
                        last_dstblk->flags = blk->flags;
+                       if (last_dstblk->flags & HTX_BLK_FL_EOM)
+                               dst->flags |= HTX_FL_HAS_EOM;
                        break;
 
                default:
@@ -841,6 +845,8 @@ size_t htx_xfer(struct htx *dst, struct htx *src, size_t count, unsigned int fla
                        last_dstblk->flags = blk->flags;
                        last_dstblk->info = blk->info;
                        htx_memcpy(htx_get_blk_ptr(dst, last_dstblk), htx_get_blk_ptr(src, blk), sz);
+                       if (last_dstblk->flags & HTX_BLK_FL_EOM)
+                               dst->flags |= HTX_FL_HAS_EOM;
                        last_dstblk_sz = sz;
                        count -= meta_sz + sz;
                        ret += meta_sz + sz;
@@ -911,9 +917,9 @@ size_t htx_xfer(struct htx *dst, struct htx *src, size_t count, unsigned int fla
                }
        }
 
-       /* Everything was copied, transfer terminal HTX flags too */
+       /* Everything was copied, transfer HTX error flags too */
        if (!blk) {
-               dst->flags |= (src->flags & (HTX_FL_HAS_EOM|HTX_FL_PARSING_ERROR|HTX_FL_PROCESSING_ERROR));
+               dst->flags |= (src->flags & (HTX_FL_PARSING_ERROR|HTX_FL_PROCESSING_ERROR));
                if (!(flags & HTX_XFER_KEEP_SRC_BLKS))
                        src->flags = 0;
        }
@@ -1060,7 +1066,9 @@ struct htx_ret htx_reserve_max_data(struct htx *htx)
                goto rsv_new_block;
 
        /* Don't try to append data if the last inserted block is not of the
-        * same type */
+        * same type or if it is the end of the message */
+       if (tailblk->flags & HTX_BLK_FL_EOM)
+               goto rsv_new_block;
        if (htx_get_blk_type(tailblk) != HTX_BLK_DATA) {
                if (htx_get_blk_type(tailblk) > HTX_BLK_DATA)
                        flags |= HTX_FL_UNORDERED;
@@ -1137,7 +1145,9 @@ size_t htx_add_data(struct htx *htx, const struct ist data)
                goto add_new_block;
 
        /* Don't try to append data if the last inserted block is not of the
-        * same type */
+        * same type or if it is the end of the message */
+       if (tailblk->flags & HTX_BLK_FL_EOM)
+               goto add_new_block;
        if (htx_get_blk_type(tailblk) != HTX_BLK_DATA) {
                if (htx_get_blk_type(tailblk) > HTX_BLK_DATA)
                        flags |= HTX_FL_UNORDERED;
@@ -1209,8 +1219,11 @@ struct htx_blk *htx_add_last_data(struct htx *htx, struct ist data)
                return NULL;
 
        for (pblk = htx_get_prev_blk(htx, blk); pblk; pblk = htx_get_prev_blk(htx, pblk)) {
-               if (htx_get_blk_type(pblk) <= HTX_BLK_DATA)
+               if (htx_get_blk_type(pblk) <= HTX_BLK_DATA) {
+                       blk->flags |= (pblk->flags & HTX_BLK_FL_EOM);
+                       pblk->flags &= ~HTX_BLK_FL_EOM;
                        break;
+               }
 
                /* Swap .addr and .info fields */
                blk->flags ^= pblk->flags; pblk->flags ^= blk->flags; blk->flags ^= pblk->flags;
@@ -1227,7 +1240,10 @@ struct htx_blk *htx_add_last_data(struct htx *htx, struct ist data)
 
 /* Moves the block <blk> just before the block <ref>. Both blocks must be in the
  * HTX message <htx> and <blk> must be placed after <ref>. pointer to these
- * blocks are updated to remain valid after the move. */
+ * blocks are updated to remain valid after the move.
+ *
+ * It is the caller responsibility to take care the result remains valid.
+ */
 void htx_move_blk_before(struct htx *htx, struct htx_blk **blk, struct htx_blk **ref)
 {
        struct htx_blk *cblk, *pblk;
@@ -1236,6 +1252,12 @@ void htx_move_blk_before(struct htx *htx, struct htx_blk **blk, struct htx_blk *
        for (pblk = htx_get_prev_blk(htx, cblk); pblk; pblk = htx_get_prev_blk(htx, pblk)) {
                htx->flags |= HTX_FL_UNORDERED;
 
+               /* transfer EOM to <pblk> before swapping blocs */
+               if (cblk->flags & HTX_BLK_FL_EOM) {
+                       pblk->flags |= HTX_BLK_FL_EOM;
+                       cblk->flags &= ~HTX_BLK_FL_EOM;
+               }
+
                /* Swap .flags, .addr and .info fields */
                cblk->flags ^= pblk->flags; pblk->flags ^= cblk->flags; cblk->flags ^= pblk->flags;
                cblk->addr ^= pblk->addr; pblk->addr ^= cblk->addr; cblk->addr ^= pblk->addr;
@@ -1255,6 +1277,8 @@ void htx_move_blk_before(struct htx *htx, struct htx_blk **blk, struct htx_blk *
  * success and 0 on error.  All the message or nothing is copied. If an error
  * occurred, all blocks from <src> already appended to <dst> are truncated. On
  * success, the EOM flag is set on <dst> if also set on <src>.
+ *
+ * It is the caller responsibility to take care the result remains valid.
  */
 int htx_append_msg(struct htx *dst, const struct htx *src)
 {