diff --git a/src/mux_h1.c b/src/mux_h1.c index 6f6b95e06..96701d614 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -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>) + */ + 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;