From: William Lallemand Date: Wed, 9 Mar 2022 10:58:51 +0000 (+0100) Subject: BUG/MINOR: httpclient: consume partly the blocks when necessary X-Git-Tag: v2.6-dev4~78 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c8f1eb99b4004444c7674d48d967ea3040a62d6e;p=thirdparty%2Fhaproxy.git BUG/MINOR: httpclient: consume partly the blocks when necessary Consume partly the blocks in the httpclient I/O handler when there is not enough room in the destination buffer for the whole block or when the block is not contained entirely in the channel's output. It prevents the I/O handler to be stuck in cases when we need to modify the buffer with a filter for exemple. Must be backported in 2.5. --- diff --git a/src/http_client.c b/src/http_client.c index ad3c40c3ce..f17e805e6d 100644 --- a/src/http_client.c +++ b/src/http_client.c @@ -849,40 +849,54 @@ static void httpclient_applet_io_handler(struct appctx *appctx) /* decapsule the htx data to raw data */ for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) { - enum htx_blk_type type; - uint32_t sz; - - blk = htx_get_blk(htx, pos); - type = htx_get_blk_type(blk); - sz = htx_get_blksz(blk); - - /* we need to check if the data are part of the ouput */ - if (co_data(res) < sz) + struct htx_blk *blk = htx_get_blk(htx, pos); + enum htx_blk_type type = htx_get_blk_type(blk); + size_t count = co_data(res); + uint32_t blksz = htx_get_blksz(blk); + uint32_t room = b_room(&hc->res.buf); + uint32_t vlen; + + /* we should try to copy the maximum output data in a block, which fit + * the destination buffer */ + vlen = MIN(count, blksz); + vlen = MIN(vlen, room); + + if (vlen == 0) goto process_data; if (type == HTX_BLK_DATA) { struct ist v = htx_get_blk_value(htx, blk); - if ((b_room(&hc->res.buf) < v.len)) - goto process_data; + __b_putblk(&hc->res.buf, v.ptr, vlen); + c_rew(res, vlen); - __b_putblk(&hc->res.buf, v.ptr, v.len); - co_set_data(res, co_data(res) - sz); - htx_remove_blk(htx, blk); + if (vlen == blksz) + htx_remove_blk(htx, blk); + else + htx_cut_data_blk(htx, blk, vlen); /* the data must be processed by the caller in the receive phase */ if (hc->ops.res_payload) hc->ops.res_payload(hc); + + /* cannot copy everything, need to processs */ + if (vlen != blksz) + goto process_data; } else { + if (vlen != blksz) + goto process_data; + /* remove any block which is not a data block */ - co_set_data(res, co_data(res) - sz); + c_rew(res, blksz); htx_remove_blk(htx, blk); } } + /* if not finished, should be called again */ - if (!(htx->flags & HTX_FL_EOM)) + if (!(htx_is_empty(htx) && (htx->flags & HTX_FL_EOM))) goto more; + /* end of message, we should quit */ appctx->st0 = HTTPCLIENT_S_RES_END; break;