]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: channel/htx: Use the total HTX size in channel_htx_recv_limit()
authorChristopher Faulet <cfaulet@haproxy.com>
Tue, 2 Jul 2019 13:48:03 +0000 (15:48 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Tue, 2 Jul 2019 19:32:45 +0000 (21:32 +0200)
The receive limit of an HTX channel must be calculated against the total size of
the HTX message. Otherwise, the buffer may never be seen as full whereas the
receive limit is 0. Indeed, the function channel_htx_full() already takes care
to add a block size to the buffer's reserve (8 bytes). So if the function
channel_htx_recv_limit() also keep a block size free in addition to the buffer's
reserve, it means that at least 2 block size will be kept free but only one will
be taken into account, freezing the stream if the option http-buffer-request is
enabled.

This patch fixes the Github issue #136. It should be backported to 2.0 and
1.9. Thanks jaroslawr (Jarosław Rzeszótko) for his help.

include/common/htx.h
include/proto/channel.h

index 7d15365a37675d77a03d06846e33249accbcc59d..ca2309b00a015e0b6eff722f764a2f27e6a6bbb1 100644 (file)
@@ -616,15 +616,6 @@ static inline uint32_t htx_free_space(const struct htx *htx)
        return (htx->size - htx_used_space(htx));
 }
 
-/* Returns the maximum space usable for data in <htx>. This is in fact the
- * maximum sice for a uniq block to fill the HTX message. */
-static inline uint32_t htx_max_data_space(const struct htx *htx)
-{
-       if (!htx->size)
-               return 0;
-       return (htx->size - sizeof(htx->blocks[0]));
-}
-
 /* Returns the maximum size available to store some data in <htx> if a new block
  * is reserved.
  */
index 9dc2b991cc1e031a72046e3bb8ab764091738431..5e5d8228c20d68a3abf36085dd1b9609c76f48e6 100644 (file)
@@ -736,17 +736,17 @@ static inline int channel_htx_recv_limit(const struct channel *chn, const struct
         * cause an integer underflow in the comparison since both are unsigned
         * while maxrewrite is signed.
         * The code below has been verified for being a valid check for this :
-        *   - if (o + to_forward) overflow => return max_data_space  [ large enough ]
-        *   - if o + to_forward >= maxrw   => return max_data_space  [ large enough ]
-        *   - otherwise return max_data_space - (maxrw - (o + to_forward))
+        *   - if (o + to_forward) overflow => return htx->size  [ large enough ]
+        *   - if o + to_forward >= maxrw   => return htx->size  [ large enough ]
+        *   - otherwise return htx->size - (maxrw - (o + to_forward))
         */
        transit = co_data(chn) + chn->to_forward;
        reserve -= transit;
        if (transit < chn->to_forward ||                 // addition overflow
            transit >= (unsigned)global.tune.maxrewrite) // enough transit data
-               return htx_max_data_space(htx);
+               return htx->size;
  end:
-       return (htx_max_data_space(htx) - reserve);
+       return (htx->size - reserve);
 }
 
 /* HTX version of channel_full(). Instead of checking if INPUT data exceeds