]> git.kaiwu.me - haproxy.git/commitdiff
MEDIUM: htx: Insert headers and trailers before corresponding end-of block
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 8 Jul 2026 13:15:53 +0000 (15:15 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 18 Sep 2026 15:05:18 +0000 (17:05 +0200)
htx_add_header() and htx_add_trailer() were updated to automatically insert
the block at the right place, just before the corresponding end-of block.
Indeed, it is invalid, unexepected and probably unsupported to insert a
header after the EOH block without moving it. So it is easier to handle it
in HTX function directly.

It means that http_add_header() was simplified.

include/haproxy/htx.h
src/http_htx.c

index 0d745b851f9dd8c2b252823dfc4cb3312cc59c4a..58a714a1e0602da7c2733412d49f75005dfec6cc 100644 (file)
@@ -521,12 +521,11 @@ static inline struct htx_sl *htx_add_stline(struct htx *htx, enum htx_blk_type t
 static inline struct htx_blk *htx_add_header(struct htx *htx, const struct ist name,
                                             const struct ist value)
 {
-       struct htx_blk *blk, *tailblk;
+       struct htx_blk *blk, *prevblk;
 
        if (name.len > HTX_HDR_NAME_MAX_LEN || value.len > HTX_HDR_VALUE_MAX_LEN)
                return NULL;
 
-       tailblk = htx_get_tail_blk(htx);
        blk = htx_add_blk(htx, HTX_BLK_HDR, name.len + value.len);
        if (!blk)
                return NULL;
@@ -534,8 +533,17 @@ static inline struct htx_blk *htx_add_header(struct htx *htx, const struct ist n
        blk->info += (value.len << 8) + name.len;
        ist2bin_lc(htx_get_blk_ptr(htx, blk), name);
        memcpy(htx_get_blk_ptr(htx, blk)  + name.len, value.ptr, value.len);
-       if (tailblk && htx_get_blk_type(tailblk) >= HTX_BLK_EOH)
-               htx->flags |= HTX_FL_UNORDERED;
+
+       for (prevblk = htx_get_prev_blk(htx, blk);
+            prevblk && htx_get_blk_type(prevblk) > HTX_BLK_HDR;
+            prevblk = htx_get_prev_blk(htx, blk)) {
+
+               /* Swap .addr and .info fields */
+               blk->addr ^= prevblk->addr; prevblk->addr ^= blk->addr; blk->addr ^= prevblk->addr;
+               blk->info ^= prevblk->info; prevblk->info ^= blk->info; blk->info ^= prevblk->info;
+               blk = prevblk;
+       }
+
        return blk;
 }
 
@@ -545,12 +553,11 @@ static inline struct htx_blk *htx_add_header(struct htx *htx, const struct ist n
 static inline struct htx_blk *htx_add_trailer(struct htx *htx, const struct ist name,
                                              const struct ist value)
 {
-       struct htx_blk *blk, *tailblk;
+       struct htx_blk *blk, *prevblk;
 
        if (name.len > HTX_HDR_NAME_MAX_LEN || value.len > HTX_HDR_VALUE_MAX_LEN)
                return NULL;
 
-       tailblk = htx_get_tail_blk(htx);
        blk = htx_add_blk(htx, HTX_BLK_TLR, name.len + value.len);
        if (!blk)
                return NULL;
@@ -558,8 +565,17 @@ static inline struct htx_blk *htx_add_trailer(struct htx *htx, const struct ist
        blk->info += (value.len << 8) + name.len;
        ist2bin_lc(htx_get_blk_ptr(htx, blk), name);
        memcpy(htx_get_blk_ptr(htx, blk)  + name.len, value.ptr, value.len);
-       if (tailblk && htx_get_blk_type(tailblk) >= HTX_BLK_EOT)
-               htx->flags |= HTX_FL_UNORDERED;
+
+       for (prevblk = htx_get_prev_blk(htx, blk);
+            prevblk && htx_get_blk_type(prevblk) > HTX_BLK_TLR;
+            prevblk = htx_get_prev_blk(htx, blk)) {
+
+               /* Swap .addr and .info fields */
+               blk->addr ^= prevblk->addr; prevblk->addr ^= blk->addr; blk->addr ^= prevblk->addr;
+               blk->info ^= prevblk->info; prevblk->info ^= blk->info; blk->info ^= prevblk->info;
+               blk = prevblk;
+       }
+
        return blk;
 }
 
index b74f49dabee35df59129aad95a40fd5c6de1b692..bc559221b5aac3d30ab75fde837f2a67586ebdf5 100644 (file)
@@ -285,41 +285,12 @@ int http_match_header(const struct htx *htx, const struct my_regex *re, struct h
  */
 int http_add_header(struct htx *htx, const struct ist n, const struct ist v, int update_authority)
 {
-       struct htx_blk *blk;
-       struct htx_sl *sl;
-       enum htx_blk_type type = htx_get_tail_type(htx);
-       int32_t prev;
-
-       blk = htx_add_header(htx, n, v);
-       if (!blk)
+       if (!htx_add_header(htx, n, v))
                goto fail;
 
-       if (unlikely(type < HTX_BLK_EOH))
-               goto end;
-
-       /* <blk> is the head, swap it iteratively with its predecessor to place
-        * it just before the end-of-header block. So blocks remains ordered. */
-       for (prev = htx_get_prev(htx, htx->tail); prev != htx->first; prev = htx_get_prev(htx, prev)) {
-               struct htx_blk   *pblk = htx_get_blk(htx, prev);
-               enum htx_blk_type ptype = htx_get_blk_type(pblk);
-
-               /* Swap .addr and .info fields */
-               blk->addr ^= pblk->addr; pblk->addr ^= blk->addr; blk->addr ^= pblk->addr;
-               blk->info ^= pblk->info; pblk->info ^= blk->info; blk->info ^= pblk->info;
-
-               if (blk->addr == pblk->addr)
-                       blk->addr += htx_get_blksz(pblk);
-
-               /* Stop when end-of-header is reached */
-               if (ptype == HTX_BLK_EOH)
-                       break;
-
-               blk = pblk;
-       }
-
-  end:
        if (update_authority) {
-               sl = http_get_stline(htx);
+               struct htx_sl *sl = http_get_stline(htx);
+
                if (sl && (sl->flags & HTX_SL_F_HAS_AUTHORITY) && isteqi(n, ist("host"))) {
                        if (!http_update_authority(htx, sl, v))
                                goto fail;