From: Christopher Faulet Date: Wed, 8 Jul 2026 13:15:53 +0000 (+0200) Subject: MEDIUM: htx: Insert headers and trailers before corresponding end-of block X-Git-Tag: v3.5-dev8~172 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=0a9ecebdaaa36710cb4aae3a7a1feb8d9f9cf07f;p=haproxy.git MEDIUM: htx: Insert headers and trailers before corresponding end-of block 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. --- diff --git a/include/haproxy/htx.h b/include/haproxy/htx.h index 0d745b851..58a714a1e 100644 --- a/include/haproxy/htx.h +++ b/include/haproxy/htx.h @@ -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; } diff --git a/src/http_htx.c b/src/http_htx.c index b74f49dab..bc559221b 100644 --- a/src/http_htx.c +++ b/src/http_htx.c @@ -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; - - /* 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;