|
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;
|