From: Christopher Faulet Date: Tue, 3 Feb 2026 10:55:58 +0000 (+0100) Subject: MEDIUM: htx: Refactor htx defragmentation to merge data blocks X-Git-Tag: v3.4-dev5~37 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0c6f2207fc870205c3001f2836a799838c035aff;p=thirdparty%2Fhaproxy.git MEDIUM: htx: Refactor htx defragmentation to merge data blocks When an HTX message is defragmented, the HTX DATA blocks are now merged into one block. Just like the previous commit, this will help all payload analysis, if any. However, there is an exception when the reference on a DATA block must be preserved, via the parameter. In that case, this DATA block is not merged with previous block. --- diff --git a/src/htx.c b/src/htx.c index 99287e461..f733e5ef5 100644 --- a/src/htx.c +++ b/src/htx.c @@ -11,6 +11,7 @@ */ #include +#include #include #include @@ -30,28 +31,30 @@ static inline __attribute__((always_inline)) void htx_memcpy(void *dst, void *sr /* Defragments an HTX message. It removes unused blocks and unwraps the payloads * part. A temporary buffer is used to do so. This function never fails. Most of * time, we need keep a ref on a specific HTX block. Thus is is set, the - * pointer on its new position, after defrag, is returned. In addition, if the - * size of the block must be altered, info must be provided (!= + * pointer on its new position, after defrag, is returned. If is a DATA + * block, no merge with any previous DATA block is performed. In addition, if + * the size of the block must be altered, info must be provided (!= * 0). But in this case, it remains the caller responsibility to update the * block content. */ -/* TODO: merge data blocks into one */ struct htx_blk *htx_defrag(struct htx *htx, struct htx_blk *blk, uint32_t blkinfo) { - struct buffer *chunk = get_trash_chunk(); - struct htx *tmp = htxbuf(chunk); + struct buffer *chunk; + struct htx *tmp; struct htx_blk *newblk, *oldblk; + enum htx_blk_type type; uint32_t new, old, blkpos; - uint32_t addr, blksz; - int32_t first = -1; + uint32_t blksz; if (htx->head == -1) return NULL; + chunk = alloc_trash_chunk(); + tmp = htxbuf(chunk); + blkpos = -1; new = 0; - addr = 0; tmp->size = htx->size; tmp->data = 0; @@ -61,16 +64,25 @@ struct htx_blk *htx_defrag(struct htx *htx, struct htx_blk *blk, uint32_t blkinf if (htx_get_blk_type(oldblk) == HTX_BLK_UNUSED) continue; + type = htx_get_blk_type(oldblk); blksz = htx_get_blksz(oldblk); - htx_memcpy((void *)tmp->blocks + addr, htx_get_blk_ptr(htx, oldblk), blksz); + switch (type) { + case HTX_BLK_DATA: + if (blk != oldblk) { + newblk = htx_add_data_atonce(tmp, htx_get_blk_value(htx, oldblk)); + break; + } + __fallthrough; + default: + newblk = htx_add_blk(tmp, type, blksz); + newblk->info = oldblk->info; + htx_memcpy(htx_get_blk_ptr(tmp, newblk), htx_get_blk_ptr(htx, oldblk), blksz); + break; + }; /* update the start-line position */ if (htx->first == old) - first = new; - - newblk = htx_get_blk(tmp, new); - newblk->addr = addr; - newblk->info = oldblk->info; + tmp->first = new; /* if is defined, save its new position */ if (blk != NULL && blk == oldblk) { @@ -78,22 +90,20 @@ struct htx_blk *htx_defrag(struct htx *htx, struct htx_blk *blk, uint32_t blkinf newblk->info = blkinfo; blkpos = new; } - - blksz = htx_get_blksz(newblk); - addr += blksz; - tmp->data += blksz; new++; } - htx->data = tmp->data; - htx->first = first; - htx->head = 0; - htx->tail = new - 1; - htx->head_addr = htx->end_addr = 0; - htx->tail_addr = addr; + BUG_ON(htx->data != tmp->data); + htx->first = tmp->first; + htx->head = tmp->head; + htx->tail = tmp->tail; + htx->head_addr = tmp->head_addr; + htx->end_addr = tmp->end_addr; + htx->tail_addr = tmp->tail_addr; htx->flags &= ~HTX_FL_FRAGMENTED; htx_memcpy((void *)htx->blocks, (void *)tmp->blocks, htx->size); + free_trash_chunk(chunk); return ((blkpos == -1) ? NULL : htx_get_blk(htx, blkpos)); }