BUG/MINOR: mux-h2: Properly handle full or truncated HTX messages on shut
On shut, truncated HTX messages were not properly handled by the H2 multiplexer. Depending on how data were emitted, a chunked HTX message without the 0-CRLF could be considered as full and an empty data with ES flag set could be emitted instead of a RST_STREAM(CANCEL) frame. In the H2 multiplexer, when a shut is performed, an HTX message is considered as truncated if more HTX data are still expected. It is based on the presence or not of the H2_SF_MORE_HTX_DATA flag on the H2 stream. However, this flag is set or unset depending on the HTX extra field value. This field is used to state how much data that must still be transferred, based on the announced data length. For a message with a content-length, this assumption is valid. But for a chunked message, it is not true. Only the length of the current chunk is announced. So we cannot rely on this field in that case to know if a message is full or not. Instead, we must rely on the HTX start-line flags to know if more HTX data are expected or not. If the xfer length is known (the HTX_SL_F_XFER_LEN flag is set on the HTX start-line), it means that more data are always expected, until the end of message is reached (the HTX_FL_EOM flag is set on the HTX message). This is true for bodyless message because the end of message is reported with the end of headers. This is also true for tunneled messages because the end of message is received before switching the H2 stream in tunnel mode. This patch must be backported as far as 2.8.
This commit is contained in:
parent
b93e419750
commit
b70921f2c1
14
src/mux_h2.c
14
src/mux_h2.c
@ -6252,6 +6252,8 @@ static size_t h2s_snd_fhdrs(struct h2s *h2s, struct htx *htx)
|
||||
BUG_ON(sl); /* Only one start-line expected */
|
||||
sl = htx_get_blk_ptr(htx, blk);
|
||||
h2s->status = sl->info.res.status;
|
||||
if (sl->flags & HTX_SL_F_XFER_LEN)
|
||||
h2s->flags |= H2_SF_MORE_HTX_DATA;
|
||||
if ((sl->flags & HTX_SL_F_BODYLESS_RESP) || h2s->status == 204 || h2s->status == 304)
|
||||
h2s->flags |= H2_SF_BODYLESS_RESP;
|
||||
if (h2s->status < 100 || h2s->status > 999) {
|
||||
@ -6412,6 +6414,7 @@ static size_t h2s_snd_fhdrs(struct h2s *h2s, struct htx *htx)
|
||||
/* EOM+empty: we may need to add END_STREAM except for 1xx
|
||||
* responses and tunneled response.
|
||||
*/
|
||||
h2s->flags &= ~H2_SF_MORE_HTX_DATA;
|
||||
if (!(h2s->flags & H2_SF_BODY_TUNNEL) || h2s->status >= 300)
|
||||
es_now = 1;
|
||||
}
|
||||
@ -6571,6 +6574,8 @@ static size_t h2s_snd_bhdrs(struct h2s *h2s, struct htx *htx)
|
||||
sl = htx_get_blk_ptr(htx, blk);
|
||||
meth = htx_sl_req_meth(sl);
|
||||
uri = htx_sl_req_uri(sl);
|
||||
if (sl->flags & HTX_SL_F_XFER_LEN)
|
||||
h2s->flags |= H2_SF_MORE_HTX_DATA;
|
||||
if ((sl->flags & HTX_SL_F_BODYLESS_RESP) || sl->info.req.meth == HTTP_METH_HEAD)
|
||||
h2s->flags |= H2_SF_BODYLESS_RESP;
|
||||
if (unlikely(uri.len == 0)) {
|
||||
@ -6839,6 +6844,7 @@ static size_t h2s_snd_bhdrs(struct h2s *h2s, struct htx *htx)
|
||||
/* EOM+empty: we may need to add END_STREAM (except for CONNECT
|
||||
* request)
|
||||
*/
|
||||
h2s->flags &= ~H2_SF_MORE_HTX_DATA;
|
||||
if (!(h2s->flags & H2_SF_BODY_TUNNEL))
|
||||
es_now = 1;
|
||||
}
|
||||
@ -7009,6 +7015,7 @@ static size_t h2s_make_data(struct h2s *h2s, struct buffer *buf, size_t count)
|
||||
/* EOM+empty: we may need to add END_STREAM (except for tunneled
|
||||
* message)
|
||||
*/
|
||||
h2s->flags &= ~H2_SF_MORE_HTX_DATA;
|
||||
if (!(h2s->flags & H2_SF_BODY_TUNNEL))
|
||||
es_now = 1;
|
||||
}
|
||||
@ -7145,6 +7152,7 @@ static size_t h2s_make_data(struct h2s *h2s, struct buffer *buf, size_t count)
|
||||
/* EOM+empty: we may need to add END_STREAM (except for tunneled
|
||||
* message)
|
||||
*/
|
||||
h2s->flags &= ~H2_SF_MORE_HTX_DATA;
|
||||
if (!(h2s->flags & H2_SF_BODY_TUNNEL))
|
||||
es_now = 1;
|
||||
}
|
||||
@ -7227,6 +7235,7 @@ static size_t h2s_skip_data(struct h2s *h2s, struct buffer *buf, size_t count)
|
||||
if (!(htx->flags & HTX_FL_EOM) || !htx_is_unique_blk(htx, blk))
|
||||
goto skip_data;
|
||||
|
||||
h2s->flags &= ~H2_SF_MORE_HTX_DATA;
|
||||
/* Here, it is the last block and it is also the end of the message. So
|
||||
* we can emit an empty DATA frame with the ES flag set
|
||||
*/
|
||||
@ -7670,11 +7679,6 @@ static size_t h2_snd_buf(struct stconn *sc, struct buffer *buf, size_t count, in
|
||||
if (!(h2s->flags & H2_SF_OUTGOING_DATA) && count)
|
||||
h2s->flags |= H2_SF_OUTGOING_DATA;
|
||||
|
||||
if (htx->extra && htx->extra != HTX_UNKOWN_PAYLOAD_LENGTH)
|
||||
h2s->flags |= H2_SF_MORE_HTX_DATA;
|
||||
else
|
||||
h2s->flags &= ~H2_SF_MORE_HTX_DATA;
|
||||
|
||||
if (h2s->id == 0) {
|
||||
int32_t id = h2c_get_next_sid(h2s->h2c);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user