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;