You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

79 lines
4.0 KiB

commit 9a408abbb8559df5718bc696bd9c3934c6500d63
Author: Willy Tarreau <w@1wt.eu>
Date: Fri Aug 23 08:11:36 2019 +0200
BUG/MEDIUM: mux-h1: do not truncate trailing 0CRLF on buffer boundary
The H1 message parser calls the various message block parsers with an
offset indicating where in the buffer to start from, and only consumes
the data at the end of the parsing. The headers and trailers parsers
have a condition detecting if a headers or trailers block is too large
to fit into the buffer. This is detected by an incomplete block while
the buffer is full. Unfortunately it doesn't take into account the fact
that the block may be parsed after other blocks that are still present
in the buffer, resulting in aborting some transfers early as reported
in issue #231. This typically happens if a trailers block is incomplete
at the end of a buffer full of data, which typically happens with data
sizes multiple of the buffer size minus less than the trailers block
size. It also happens with the CRLF that follows the 0-sized chunk of
any transfer-encoded contents is itself on such a boundary since this
CRLF is technically part of the trailers block. This can be reproduced
by asking a server to retrieve exactly 31532 or 31533 bytes of static
data using chunked encoding with curl, which reports:
transfer closed with outstanding read data remaining
This issue was revealed in 2.0 and does not affect 1.9 because in 1.9
the trailers block was processed at once as part of the data block
processing, and would simply give up and wait for the rest of the data
to arrive.
It's interesting to note that the headers block parsing is also affected
by this issue but in practice it has a much more limited impact since a
headers block is normally only parsed at the beginning of a buffer. The
only case where it seems to matter is when dealing with a response buffer
full of 100-continue header blocks followed by a regular header block,
which will then be rejected for the same reason.
This fix must be backported to 2.0 and partially to 1.9 (the headers
block part).
(cherry picked from commit 347f464d4e5a8a2bf3acd2411a6c8228e605e7f6)
Signed-off-by: Willy Tarreau <w@1wt.eu>
diff --git a/src/mux_h1.c b/src/mux_h1.c
index fa694c41..01f225a2 100644
--- a/src/mux_h1.c
+++ b/src/mux_h1.c
@@ -995,10 +995,11 @@ static size_t h1_process_headers(struct h1s *h1s, struct h1m *h1m, struct htx *h
ret = h1_headers_to_hdr_list(b_peek(buf, *ofs), b_tail(buf),
hdrs, sizeof(hdrs)/sizeof(hdrs[0]), h1m, &h1sl);
if (ret <= 0) {
- /* Incomplete or invalid message. If the buffer is full, it's an
- * error because headers are too large to be handled by the
- * parser. */
- if (ret < 0 || (!ret && !buf_room_for_htx_data(buf)))
+ /* Incomplete or invalid message. If the input buffer only
+ * contains headers and is full, which is detected by it being
+ * full and the offset to be zero, it's an error because
+ * headers are too large to be handled by the parser. */
+ if (ret < 0 || (!ret && !*ofs && !buf_room_for_htx_data(buf)))
goto error;
goto end;
}
@@ -1339,10 +1340,11 @@ static size_t h1_process_trailers(struct h1s *h1s, struct h1m *h1m, struct htx *
ret = h1_headers_to_hdr_list(b_peek(buf, *ofs), b_tail(buf),
hdrs, sizeof(hdrs)/sizeof(hdrs[0]), &tlr_h1m, NULL);
if (ret <= 0) {
- /* Incomplete or invalid trailers. If the buffer is full, it's
- * an error because traliers are too large to be handled by the
- * parser. */
- if (ret < 0 || (!ret && !buf_room_for_htx_data(buf)))
+ /* Incomplete or invalid trailers. If the input buffer only
+ * contains trailers and is full, which is detected by it being
+ * full and the offset to be zero, it's an error because
+ * trailers are too large to be handled by the parser. */
+ if (ret < 0 || (!ret && !*ofs && !buf_room_for_htx_data(buf)))
goto error;
goto end;
}