diff --git a/include/haproxy/htx.h b/include/haproxy/htx.h index a6c62f906..52efb931b 100644 --- a/include/haproxy/htx.h +++ b/include/haproxy/htx.h @@ -57,6 +57,7 @@ struct htx_blk *htx_add_trailer(struct htx *htx, const struct ist name, const st struct htx_blk *htx_add_all_headers(struct htx *htx, const struct http_hdr *hdrs); struct htx_blk *htx_add_all_trailers(struct htx *htx, const struct http_hdr *hdrs); struct htx_blk *htx_add_endof(struct htx *htx, enum htx_blk_type type); +struct htx_ret htx_reserve_max_data(struct htx *htx); struct htx_blk *htx_add_data_atonce(struct htx *htx, struct ist data); size_t htx_add_data(struct htx *htx, const struct ist data); struct htx_blk *htx_add_last_data(struct htx *htx, struct ist data); diff --git a/src/htx.c b/src/htx.c index 76b65493e..6a4fe2d35 100644 --- a/src/htx.c +++ b/src/htx.c @@ -935,6 +935,69 @@ struct htx_blk *htx_add_endof(struct htx *htx, enum htx_blk_type type) return blk; } +/* Reserves the maximum possible size for an HTX data block, by extending an + * existing one or by creating a now one. It returns a compound result with the + * HTX block and the position where new data must be inserted (0 for a new + * block). If an error occurs or if there is no space left, NULL is returned + * instead of a pointer on an HTX block. + */ +struct htx_ret htx_reserve_max_data(struct htx *htx) +{ + struct htx_blk *blk, *tailblk; + uint32_t sz, room; + int32_t len = htx_free_data_space(htx); + + if (htx->head == -1) + goto rsv_new_block; + + if (!len) + return (struct htx_ret){.ret = 0, .blk = NULL}; + + /* get the tail and head block */ + tailblk = htx_get_tail_blk(htx); + if (tailblk == NULL) + goto rsv_new_block; + sz = htx_get_blksz(tailblk); + + /* Don't try to append data if the last inserted block is not of the + * same type */ + if (htx_get_blk_type(tailblk) != HTX_BLK_DATA) + goto rsv_new_block; + + /* + * Same type and enough space: append data + */ + if (!htx->head_addr) { + if (tailblk->addr+sz != htx->tail_addr) + goto rsv_new_block; + room = (htx_pos_to_addr(htx, htx->tail) - htx->tail_addr); + } + else { + if (tailblk->addr+sz != htx->head_addr) + goto rsv_new_block; + room = (htx->end_addr - htx->head_addr); + } + BUG_ON((int32_t)room < 0); + if (room < len) + len = room; + + append_data: + htx_change_blk_value_len(htx, tailblk, sz+len); + + BUG_ON((int32_t)htx->tail_addr < 0); + BUG_ON((int32_t)htx->head_addr < 0); + BUG_ON(htx->end_addr > htx->tail_addr); + BUG_ON(htx->head_addr > htx->end_addr); + return (struct htx_ret){.ret = sz, .blk = tailblk}; + + rsv_new_block: + /* FIXME: check data.len (< 256MB) */ + blk = htx_add_blk(htx, HTX_BLK_DATA, len); + if (!blk) + return (struct htx_ret){.ret = 0, .blk = NULL}; + blk->info += len; + return (struct htx_ret){.ret = 0, .blk = blk}; +} /* Adds an HTX block of type DATA in . It first tries to append data if * possible. It returns the number of bytes consumed from , which may be