|
|
- commit 620381599324e15403002270637a3b677c3fe7e5
- Author: Willy Tarreau <w@1wt.eu>
- Date: Fri Aug 23 09:29:29 2019 +0200
-
- BUG/MEDIUM: mux-h1: do not report errors on transfers ending on buffer full
-
- If a receipt ends with the HTX buffer full and everything is completed except
- appending the HTX EOM block, we end up detecting an error because the H1
- parser did not switch to H1_MSG_DONE yet while all conditions for an end of
- stream and end of buffer are met. This can be detected by retrieving 31532
- or 31533 chunk-encoded bytes over H1 and seeing haproxy log "SD--" at the
- end of a successful transfer.
-
- Ideally the EOM part should be totally independent on the H1 message state
- since the block was really parsed and finished. So we should switch to a
- last state requiring to send only EOM. However this needs a few risky
- changes. This patch aims for simplicity and backport safety, thus it only
- adds a flag to the H1 stream indicating that an EOM is still needed, and
- excludes this condition from the ones used to detect end of processing. A
- cleaner approach needs to be studied, either by adding a state before DONE
- or by setting DONE once the various blocks are parsed and before trying to
- send EOM.
-
- This fix must be backported to 2.0. The issue does not seem to affect 1.9
- though it is not yet known why, probably that it is related to the different
- encoding of trailers which always leaves a bit of room to let EOM be stored.
-
- (cherry picked from commit 0bb5a5c4b5ad375b1254c2e8bec2dd5ea85d6ebb)
- Signed-off-by: Willy Tarreau <w@1wt.eu>
-
- diff --git a/src/mux_h1.c b/src/mux_h1.c
- index 01f225a2..b9a37ce5 100644
- --- a/src/mux_h1.c
- +++ b/src/mux_h1.c
- @@ -67,7 +67,8 @@
- #define H1S_F_BUF_FLUSH 0x00000100 /* Flush input buffer and don't read more data */
- #define H1S_F_SPLICED_DATA 0x00000200 /* Set when the kernel splicing is in used */
- #define H1S_F_HAVE_I_TLR 0x00000800 /* Set during input process to know the trailers were processed */
- -/* 0x00001000 .. 0x00002000 unused */
- +#define H1S_F_APPEND_EOM 0x00001000 /* Send EOM to the HTX buffer */
- +/* 0x00002000 .. 0x00002000 unused */
- #define H1S_F_HAVE_O_CONN 0x00004000 /* Set during output process to know connection mode was processed */
-
- /* H1 connection descriptor */
- @@ -954,9 +955,12 @@ static size_t h1_eval_htx_res_size(struct h1m *h1m, union h1_sl *h1sl, struct ht
- */
- static size_t h1_process_eom(struct h1s *h1s, struct h1m *h1m, struct htx *htx, size_t max)
- {
- - if (max < sizeof(struct htx_blk) + 1 || !htx_add_endof(htx, HTX_BLK_EOM))
- + if (max < sizeof(struct htx_blk) + 1 || !htx_add_endof(htx, HTX_BLK_EOM)) {
- + h1s->flags |= H1S_F_APPEND_EOM;
- return 0;
- + }
-
- + h1s->flags &= ~H1S_F_APPEND_EOM;
- h1m->state = H1_MSG_DONE;
- h1s->cs->flags |= CS_FL_EOI;
- return (sizeof(struct htx_blk) + 1);
- @@ -1472,7 +1476,8 @@ static size_t h1_process_input(struct h1c *h1c, struct buffer *buf, size_t count
- else if (h1s_data_pending(h1s) && !htx_is_empty(htx))
- h1s->cs->flags |= CS_FL_RCV_MORE | CS_FL_WANT_ROOM;
-
- - if ((h1s->flags & H1S_F_REOS) && (!h1s_data_pending(h1s) || htx_is_empty(htx))) {
- + if (((h1s->flags & (H1S_F_REOS|H1S_F_APPEND_EOM)) == H1S_F_REOS) &&
- + (!h1s_data_pending(h1s) || htx_is_empty(htx))) {
- h1s->cs->flags |= CS_FL_EOS;
- if (h1m->state > H1_MSG_LAST_LF && h1m->state < H1_MSG_DONE)
- h1s->cs->flags |= CS_FL_ERROR;
|