From: Christopher Faulet Date: Wed, 12 Dec 2018 09:32:09 +0000 (+0100) Subject: BUG/MEDIUM: mux-h1: Fix the zero-copy on output for chunked messages X-Git-Tag: v1.9-dev11~83 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=adb222004120a3ab242d04469e08e44d8ae9c35b;p=thirdparty%2Fhaproxy.git BUG/MEDIUM: mux-h1: Fix the zero-copy on output for chunked messages The commit 3815b227f ("MEDIUM: mux-h1: implement true zero-copy of DATA blocks") broke the output of chunked messages. When the zero-copy was performed on such messages, no chunk size was emitted nor ending CRLF. Now, the chunked envelope is added when necessary. We have at least the size of the struct htx to emit it. So 40 bytes for now. It should be enough. --- diff --git a/src/mux_h1.c b/src/mux_h1.c index baaf0dfedc..da5d5c17e2 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -839,6 +839,34 @@ static void h1_capture_bad_message(struct h1c *h1c, struct h1s *h1s, &ctx, h1_show_error_snapshot); } +/* Emit the chunksize followed by a CRLF in front of data of the buffer + * . It goes backwards and starts with the byte before the buffer's + * head. The caller is responsible for ensuring there is enough room left before + * the buffer's head for the string. + */ +static void h1_emit_chunk_size(struct buffer *buf, size_t chksz) +{ + char *beg, *end; + + beg = end = b_head(buf); + *--beg = '\n'; + *--beg = '\r'; + do { + *--beg = hextab[chksz & 0xF]; + } while (chksz >>= 4); + buf->head -= (end - beg); + b_add(buf, end - beg); +} + +/* Emit a CRLF after the data of the buffer . The caller is responsible for + * ensuring there is enough room left in the buffer for the string. */ +static void h1_emit_chunk_crlf(struct buffer *buf) +{ + *(b_peek(buf, b_data(buf))) = '\r'; + *(b_peek(buf, b_data(buf) + 1)) = '\n'; + b_add(buf, 2); +} + /* * Parse HTTP/1 headers. It returns the number of bytes parsed if > 0, or 0 if * it couldn't proceed. Parsing errors are reported by setting H1S_F_*_ERROR @@ -1389,6 +1417,16 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun buf->area = old_area; buf->data = buf->head = 0; + + /* The message is chunked. We need to emit the chunk + * size. We have at least the size of the struct htx to + * write the chunk envelope. It should be enough. + */ + if (h1m->flags & H1_MF_CHNK) { + h1_emit_chunk_size(&h1c->obuf, count); + h1_emit_chunk_crlf(&h1c->obuf); + } + total += count; goto out; }