MEDIUM: mux-h1: Support zero-copy forwarding for chunks with an unknown size

Till now, for chunked messages, the H1 mux used the size requested during
the zero-copy forwarding negotiation as the chunk size. And till now, this
was accurate because the requested size was indeed the chunk size on the
producer side.

But this will be a problem to implement the zero-copy forwarding on some
applets because the content size is not known during the nego but only when
it is produced. Thanks to previous patches, it is now possible to know the
requested size is not exact and we are able to reserve a larger space to
write the chunk size later, in h1_done_ff(), with some padding.
This commit is contained in:
Christopher Faulet 2024-01-25 15:00:10 +01:00
parent dcb964f8db
commit 91b77c1632

View File

@ -4450,7 +4450,7 @@ static size_t h1_nego_ff(struct stconn *sc, struct buffer *input, size_t count,
struct h1s *h1s = __sc_mux_strm(sc);
struct h1c *h1c = h1s->h1c;
struct h1m *h1m = (!(h1c->flags & H1C_F_IS_BACK) ? &h1s->res : &h1s->req);
size_t ret = 0;
size_t sz, offset = 0, ret = 0;
TRACE_ENTER(H1_EV_STRM_SEND, h1c->conn, h1s, 0, (size_t[]){count});
@ -4487,9 +4487,18 @@ static size_t h1_nego_ff(struct stconn *sc, struct buffer *input, size_t count,
h1m->curr_len = count;
}
else {
/* XXX: Unsupported for now but will be added soon ! */
h1s->sd->iobuf.flags |= IOBUF_FL_NO_FF;
goto out;
/* The producer does not know the chunk size, thus this will be emitted at the
* end, in done_ff(). So splicing cannot be used (see TODO below).
* We will reserve 12 bytes to handle at most 4Go chunk with all CRLFs !
* (<8-bytes SIZE><CRLF><CHUNK-DATA><CRLF>)
*/
if (count > MAX_RANGE(unsigned int))
count = MAX_RANGE(unsigned int);
offset = 12;
/* Add 2 more bytes to finish the previous chunk */
if (h1m->state == H1_MSG_CHUNK_CRLF)
offset += 2;
goto no_splicing;
}
}
}
@ -4514,6 +4523,7 @@ static size_t h1_nego_ff(struct stconn *sc, struct buffer *input, size_t count,
TRACE_DEVEL("Unable to allocate pipe for splicing, fallback to buffer", H1_EV_STRM_SEND, h1c->conn, h1s);
}
no_splicing:
if (!h1_get_buf(h1c, &h1c->obuf)) {
h1c->flags |= H1C_F_OUT_ALLOC;
TRACE_STATE("waiting for opposite h1c obuf allocation", H1_EV_STRM_SEND|H1_EV_H1S_BLK, h1c->conn, h1s);
@ -4523,13 +4533,11 @@ static size_t h1_nego_ff(struct stconn *sc, struct buffer *input, size_t count,
if (b_space_wraps(&h1c->obuf))
b_slow_realign(&h1c->obuf, trash.area, b_data(&h1c->obuf));
h1s->sd->iobuf.buf = &h1c->obuf;
h1s->sd->iobuf.offset = 0;
h1s->sd->iobuf.data = 0;
/* Cannot forward more than available room in output buffer */
if (count > b_room(&h1c->obuf))
count = b_room(&h1c->obuf);
sz = b_contig_space(&h1c->obuf) - offset;
if (count > sz)
count = sz;
if (!count) {
h1c->flags |= H1C_F_OUT_FULL;
@ -4538,6 +4546,10 @@ static size_t h1_nego_ff(struct stconn *sc, struct buffer *input, size_t count,
goto out;
}
h1s->sd->iobuf.buf = &h1c->obuf;
h1s->sd->iobuf.offset = offset;
h1s->sd->iobuf.data = 0;
/* forward remaining input data */
if (b_data(input)) {
size_t xfer = count;
@ -4584,6 +4596,16 @@ static size_t h1_done_ff(struct stconn *sc)
if (b_room(&h1c->obuf) == sd->iobuf.offset)
h1c->flags |= H1C_F_OUT_FULL;
if (sd->iobuf.offset) {
b_add(&h1c->obuf, sd->iobuf.offset);
b_del(&h1c->obuf, sd->iobuf.offset);
h1_prepend_chunk_size(&h1c->obuf, sd->iobuf.data, sd->iobuf.offset - ((h1m->state == H1_MSG_CHUNK_CRLF) ? 4 : 2));
h1_append_chunk_crlf(&h1c->obuf);
if (h1m->state == H1_MSG_CHUNK_CRLF)
h1_prepend_chunk_crlf(&h1c->obuf);
h1m->state = H1_MSG_CHUNK_SIZE;
}
total = sd->iobuf.data;
sd->iobuf.buf = NULL;
sd->iobuf.offset = 0;