From: Willy Tarreau Date: Tue, 28 May 2019 08:30:11 +0000 (+0200) Subject: MINOR: htx: make htx_add_data() return the transmitted byte count X-Git-Tag: v2.0-dev5~19 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0a7ef02074962152125af897492162a4bbb7bf07;p=thirdparty%2Fhaproxy.git MINOR: htx: make htx_add_data() return the transmitted byte count In order to later allow htx_add_data() to transmit partial blocks and avoid defragmenting the buffer, we'll need to return the number of bytes consumed. This first modification makes the function do this and its callers take this into account. At the moment the function still works atomically so it returns either the block size or zero. However all call places have been adapted to consider any value between zero and the block size. --- diff --git a/include/common/htx.h b/include/common/htx.h index 463f7299bf..fd0871c529 100644 --- a/include/common/htx.h +++ b/include/common/htx.h @@ -186,7 +186,7 @@ struct htx_blk *htx_add_blk_type_size(struct htx *htx, enum htx_blk_type type, u struct htx_blk *htx_add_all_headers(struct htx *htx, const struct http_hdr *hdrs); struct htx_blk *htx_add_endof(struct htx *htx, enum htx_blk_type type); struct htx_blk *htx_add_data_atonce(struct htx *htx, const struct ist data); -struct htx_blk *htx_add_data(struct htx *htx, const struct ist data); +size_t htx_add_data(struct htx *htx, const struct ist data); struct htx_blk *htx_add_trailer(struct htx *htx, const struct ist tlr); struct htx_blk *htx_add_data_before(struct htx *htx, const struct htx_blk *ref, const struct ist data); diff --git a/src/cache.c b/src/cache.c index 83aacd136d..e390b21682 100644 --- a/src/cache.c +++ b/src/cache.c @@ -957,8 +957,7 @@ static size_t htx_cache_dump_data(struct appctx *appctx, struct htx *htx, sz = MIN(len, shctx->block_size - offset); data = ist2((const char *)shblk->data + offset, sz); if (type == HTX_BLK_DATA) { - if (!htx_add_data(htx, data)) - break; + sz = htx_add_data(htx, data); } else { /* HTX_BLK_TLR */ if (!htx_add_trailer(htx, data)) @@ -968,7 +967,7 @@ static size_t htx_cache_dump_data(struct appctx *appctx, struct htx *htx, offset += sz; len -= sz; total += sz; - if (!len) + if (!len || sz < data.len) break; offset = 0; } diff --git a/src/hlua.c b/src/hlua.c index 3c9c70a78e..a3fd57b915 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -4568,8 +4568,7 @@ __LJMP static int hlua_applet_htx_send_yield(lua_State *L, int status, lua_KCont max = len - l; /* Copy data. */ - if (!htx_add_data(htx, ist2(data + l, max))) - goto snd_yield; + max = htx_add_data(htx, ist2(data + l, max)); channel_add_input(res, max); /* update counters. */ diff --git a/src/http_htx.c b/src/http_htx.c index b9501bed73..9892fd32ac 100644 --- a/src/http_htx.c +++ b/src/http_htx.c @@ -657,9 +657,11 @@ static struct htx *http_str_to_htx(struct buffer *buf, struct ist raw) goto error; sl->info.res.status = h1sl.st.status; - if (raw.len > ret) { - if (!htx_add_data(htx, ist2(raw.ptr + ret, raw.len - ret))) + while (raw.len > ret) { + int sent = htx_add_data(htx, ist2(raw.ptr + ret, raw.len - ret)); + if (!sent) goto error; + ret += sent; } if (!htx_add_endof(htx, HTX_BLK_EOM)) goto error; diff --git a/src/htx.c b/src/htx.c index 2aeb077f2f..32e23d115f 100644 --- a/src/htx.c +++ b/src/htx.c @@ -758,11 +758,18 @@ struct htx_blk *htx_add_endof(struct htx *htx, enum htx_blk_type type) /* Adds an HTX block of type DATA in . It first tries to append data if - * possible. It returns the new block on success. Otherwise, it returns NULL. + * possible. It returns the number of bytes consumed from , which may be + * zero if nothing could be copied. */ -struct htx_blk *htx_add_data(struct htx *htx, const struct ist data) +size_t htx_add_data(struct htx *htx, const struct ist data) { - return htx_add_data_atonce(htx, data); + struct htx_blk *blk; + + blk = htx_add_data_atonce(htx, data); + if (blk) + return data.len; + else + return 0; } /* Adds an HTX block of type TLR in . It returns the new block on diff --git a/src/mux_h1.c b/src/mux_h1.c index d1e7c1d76b..ef622bd2b6 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -1143,6 +1143,8 @@ static size_t h1_process_data(struct h1s *h1s, struct h1m *h1m, struct htx *htx, * => we can swap the buffers and place an htx header into * the target buffer instead */ + int32_t try = ret; + if (unlikely(htx_is_empty(htx) && ret == b_data(buf) && !*ofs && b_head_ofs(buf) == sizeof(struct htx))) { void *raw_area = buf->area; @@ -1162,12 +1164,15 @@ static size_t h1_process_data(struct h1s *h1s, struct h1m *h1m, struct htx *htx, * empty pre-initialized HTX header */ } - else if (!htx_add_data(htx, ist2(b_peek(buf, *ofs), ret))) - goto end; + else { + ret = htx_add_data(htx, ist2(b_peek(buf, *ofs), try)); + } h1m->curr_len -= ret; max -= sizeof(struct htx_blk) + ret; *ofs += ret; total += ret; + if (ret < try) + goto end; } if (!h1m->curr_len) { @@ -1220,12 +1225,15 @@ static size_t h1_process_data(struct h1s *h1s, struct h1m *h1m, struct htx *htx, ret = b_contig_data(buf, *ofs); if (ret) { - if (!htx_add_data(htx, ist2(b_peek(buf, *ofs), ret))) - goto end; + int32_t try = ret; + + ret = htx_add_data(htx, ist2(b_peek(buf, *ofs), try)); h1m->curr_len -= ret; max -= sizeof(struct htx_blk) + ret; *ofs += ret; total += ret; + if (ret < try) + goto end; } if (!h1m->curr_len) { h1m->state = H1_MSG_CHUNK_CRLF; @@ -1291,11 +1299,14 @@ static size_t h1_process_data(struct h1s *h1s, struct h1m *h1m, struct htx *htx, ret = b_contig_data(buf, *ofs); if (ret) { - if (!htx_add_data(htx, ist2(b_peek(buf, *ofs), ret))) - goto end; + int32_t try = ret; + + ret = htx_add_data(htx, ist2(b_peek(buf, *ofs), try)); *ofs += ret; total = ret; + if (ret < try) + goto end; } } diff --git a/src/mux_h2.c b/src/mux_h2.c index 6bec578b62..7d29a7d1f6 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -3802,6 +3802,8 @@ try_again: } if (htx) { + unsigned int sent; + block1 = htx_free_data_space(htx); if (!block1) { h2c->flags |= H2_CF_DEM_SFULL; @@ -3815,10 +3817,7 @@ try_again: if (flen > block1) flen = block1; - if (!htx_add_data(htx, ist2(b_head(&h2c->dbuf), flen))) { - h2c->flags |= H2_CF_DEM_SFULL; - goto fail; - } + sent = htx_add_data(htx, ist2(b_head(&h2c->dbuf), flen)); b_del(&h2c->dbuf, flen); h2c->dfl -= flen; @@ -3829,6 +3828,12 @@ try_again: h2s->body_len -= flen; htx->extra = h2s->body_len; } + + if (sent < flen) { + h2c->flags |= H2_CF_DEM_SFULL; + goto fail; + } + goto try_again; } else if (unlikely(b_space_wraps(csbuf) && diff --git a/src/proto_htx.c b/src/proto_htx.c index 0bb1eb2fd3..27150a8ed5 100644 --- a/src/proto_htx.c +++ b/src/proto_htx.c @@ -5502,7 +5502,18 @@ static int htx_reply_40x_unauthorized(struct stream *s, const char *auth_realm) goto fail; if (status == 407 && !htx_add_header(htx, ist("Proxy-Authenticate"), ist2(trash.area, trash.data))) goto fail; - if (!htx_add_endof(htx, HTX_BLK_EOH) || !htx_add_data(htx, body) || !htx_add_endof(htx, HTX_BLK_EOM)) + if (!htx_add_endof(htx, HTX_BLK_EOH)) + goto fail; + + while (body.len) { + size_t sent = htx_add_data(htx, body); + if (!sent) + goto fail; + body.ptr += sent; + body.len -= sent; + } + + if (!htx_add_endof(htx, HTX_BLK_EOM)) goto fail; data = htx->data - co_data(res); diff --git a/src/stats.c b/src/stats.c index 9c3bf7c14f..4b994b72c3 100644 --- a/src/stats.c +++ b/src/stats.c @@ -258,7 +258,7 @@ static int stats_putchk(struct channel *chn, struct htx *htx, struct buffer *chk if (htx) { if (chk->data >= channel_htx_recv_max(chn, htx)) return 0; - if (!htx_add_data(htx, ist2(chk->area, chk->data))) + if (!htx_add_data_atonce(htx, ist2(chk->area, chk->data))) return 0; channel_add_input(chn, chk->data); chk->data = 0;