BUG/MEDIUM: stream-int: Defrag HTX message in si_cs_recv() if necessary
authorChristopher Faulet <cfaulet@haproxy.com>
Tue, 21 Sep 2021 13:22:12 +0000 (15:22 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Tue, 19 Oct 2021 13:44:15 +0000 (15:44 +0200)
The stream interface is now responsible for defragmenting the HTX message of
the input channel if necessary, before calling the mux's .rcv_buf()
function. The defrag is performed if the underlying buffer contains only
input data while the HTX message free space is not contiguous.

The defrag is important here to be sure the mux and the app layer have the
same criteria to decide if a buffer is full or not. Otherwise, the app layer
may wait for more data because the buffer is not full while the mux is
blocked because it needs more space to proceed.

This patch depends on following commits:

  * MINOR: htx: Add an HTX flag to know when a message is fragmented
  * MINOR: htx: Add a function to know if the free space wraps

This patch is related to the issue #1362. It may be backported as far as 2.0
after some observation period (not sure it is required or not).

(cherry picked from commit 2bc364c19105c12dc1dd6b043e81c48b184d4174)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit 8d521427742f12b4377c0b01672a278ee974b8ac)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>

src/stream_interface.c

index 520d43d..b54162f 100644 (file)
@@ -1329,6 +1329,22 @@ int si_cs_recv(struct conn_stream *cs)
        if (!si_alloc_ibuf(si, &(si_strm(si)->buffer_wait)))
                goto end_recv;
 
+       /* For an HTX stream, if the buffer is stuck (no output data with some
+        * input data) and if the HTX message is fragmented or if its free space
+        * wraps, we force an HTX deframentation. It is a way to have a
+        * contiguous free space nad to let the mux to copy as much data as
+        * possible.
+        *
+        * NOTE: A possible optim may be to let the mux decides if defrag is
+        *       required or not, depending on amount of data to be xferred.
+        */
+       if (IS_HTX_STRM(si_strm(si)) && !co_data(ic)) {
+               struct htx *htx = htxbuf(&ic->buf);
+
+               if (htx_is_not_empty(htx) && ((htx->flags & HTX_FL_FRAGMENTED) || htx_space_wraps(htx)))
+                       htx_defrag(htxbuf(&ic->buf), NULL, 0);
+       }
+
        /* Important note : if we're called with POLL_IN|POLL_HUP, it means the read polling
         * was enabled, which implies that the recv buffer was not full. So we have a guarantee
         * that if such an event is not handled above in splice, it will be handled here by