From 0a7ef02074962152125af897492162a4bbb7bf07 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Tue, 28 May 2019 10:30:11 +0200 Subject: [PATCH] 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. --- include/common/htx.h | 2 +- src/cache.c | 5 ++--- src/hlua.c | 3 +-- src/http_htx.c | 6 ++++-- src/htx.c | 13 ++++++++++--- src/mux_h1.c | 23 +++++++++++++++++------ src/mux_h2.c | 13 +++++++++---- src/proto_htx.c | 13 ++++++++++++- src/stats.c | 2 +- 9 files changed, 57 insertions(+), 23 deletions(-) diff --git a/include/common/htx.h b/include/common/htx.h index 463f7299b..fd0871c52 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 83aacd136..e390b2168 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 3c9c70a78..a3fd57b91 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 b9501bed7..9892fd32a 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 2aeb077f2..32e23d115 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 d1e7c1d76..ef622bd2b 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 6bec578b6..7d29a7d1f 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 0bb1eb2fd..27150a8ed 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 9c3bf7c14..4b994b72c 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;