From: Christopher Faulet Date: Wed, 8 Jul 2026 14:13:24 +0000 (+0200) Subject: MAJOR: htx: Use htx_set_eom() instead of setting HTX_FL_EOM by hand X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=cb2e1c1954f7dab22d541f92a360d493b7c0a6f8;p=haproxy.git MAJOR: htx: Use htx_set_eom() instead of setting HTX_FL_EOM by hand The function htx_set_eom() takes care to the HTX_FL_EOM on the HTX message, by first adding a EOT block if the message is empty. So let's use it wherever possible. This commit is tagged as MAJOR because it is an API change. --- diff --git a/addons/promex/service-prometheus.c b/addons/promex/service-prometheus.c index d655c4345..638774f30 100644 --- a/addons/promex/service-prometheus.c +++ b/addons/promex/service-prometheus.c @@ -2160,19 +2160,11 @@ static void promex_appctx_handle_io(struct appctx *appctx) __fallthrough; case PROMEX_ST_DONE: - /* no more data are expected. If the response buffer is - * empty, be sure to add something (EOT block in this - * case) to have something to send. It is important to - * be sure the EOM flags will be handled by the - * endpoint. - */ - if (htx_is_empty(res_htx)) { - if (!htx_add_endof(res_htx, HTX_BLK_EOT)) { - applet_have_more_data(appctx); - break; - } + /* no more data are expected */ + if (!htx_set_eom(res_htx)) { + applet_have_more_data(appctx); + break; } - res_htx->flags |= HTX_FL_EOM; applet_set_eoi(appctx); appctx->st0 = PROMEX_ST_END; __fallthrough; diff --git a/include/haproxy/htx.h b/include/haproxy/htx.h index c68e695e8..74b3ed2ee 100644 --- a/include/haproxy/htx.h +++ b/include/haproxy/htx.h @@ -837,10 +837,11 @@ static inline int htx_expect_more(const struct htx *htx) return !(htx->flags & HTX_FL_EOM); } -/* Set EOM flag in . This function is useful if the HTX message is empty. - * In this case, an EOT block is appended first to ensure the EOM will be - * forwarded as expected. This is a workaround as it is not possibly currently - * to push an empty HTX DATA block. +/* Set EOM flag in . This function must always be called to report the end + * of the message. Corresponding flags must never be added by hand, except from + * the HTX API itself. It must also be called after the last block of the + * message was added. Finally, this function takes care to add an EOT block if + * the HTX message is empty. * * Returns 1 on success else 0. */ diff --git a/src/cache.c b/src/cache.c index e20d8a5f0..1a1b6a46f 100644 --- a/src/cache.c +++ b/src/cache.c @@ -2253,7 +2253,7 @@ static void http_cache_io_handler(struct appctx *appctx) if (appctx->st0 == HTX_CACHE_EOM) { /* no more data are expected. */ - res_htx->flags |= HTX_FL_EOM; + htx_set_eom(res_htx); applet_set_eoi(appctx); se_fl_clr(appctx->sedesc, SE_FL_MAY_FASTFWD_PROD); applet_fl_clr(appctx, APPCTX_FL_FASTFWD); diff --git a/src/h1_htx.c b/src/h1_htx.c index 5b112d2f8..e5a340912 100644 --- a/src/h1_htx.c +++ b/src/h1_htx.c @@ -202,7 +202,6 @@ static int h1_postparse_req_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx h1m->flags &= ~(H1_MF_CLEN|H1_MF_CHNK); h1m->curr_len = h1m->body_len = 0; h1m->state = H1_MSG_DONE; - htx->flags |= HTX_FL_EOM; } else { if (h1sl->rq.meth == HTTP_METH_HEAD) @@ -211,7 +210,6 @@ static int h1_postparse_req_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx if (((h1m->flags & H1_MF_CLEN) && h1m->body_len == 0) || (h1m->flags & (H1_MF_XFER_LEN|H1_MF_CLEN|H1_MF_CHNK)) == H1_MF_XFER_LEN) { h1m->state = H1_MSG_DONE; - htx->flags |= HTX_FL_EOM; } } @@ -261,8 +259,10 @@ static int h1_postparse_req_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx http_scheme_based_normalize(htx); } - end: + if (h1m->state == H1_MSG_DONE) + htx_set_eom(htx); return 1; + output_full: h1m_init_req(h1m); h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR); @@ -341,7 +341,6 @@ static int h1_postparse_res_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx h1m->flags |= H1_MF_XFER_LEN; h1m->curr_len = h1m->body_len = 0; h1m->state = H1_MSG_DONE; - htx->flags |= HTX_FL_EOM; } else if ((h1m->flags & H1_MF_METH_HEAD) || (code >= 100 && code < 200) || (code == 204) || (code == 304)) { @@ -357,10 +356,8 @@ static int h1_postparse_res_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx h1m->flags |= H1_MF_XFER_LEN; h1m->curr_len = h1m->body_len = 0; - if (code >= 200) { + if (code >= 200) flags |= HTX_SL_F_BODYLESS_RESP; - htx->flags |= HTX_FL_EOM; - } h1m->state = H1_MSG_DONE; } else { @@ -370,10 +367,8 @@ static int h1_postparse_res_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx } if (((h1m->flags & H1_MF_CLEN) && h1m->body_len == 0) || - (h1m->flags & (H1_MF_XFER_LEN|H1_MF_CLEN|H1_MF_CHNK)) == H1_MF_XFER_LEN) { + (h1m->flags & (H1_MF_XFER_LEN|H1_MF_CLEN|H1_MF_CHNK)) == H1_MF_XFER_LEN) h1m->state = H1_MSG_DONE; - htx->flags |= HTX_FL_EOM; - } } flags |= h1m_htx_sl_flags(h1m); @@ -382,8 +377,10 @@ static int h1_postparse_res_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx goto error; sl->info.res.status = code; - end: + if (h1m->state == H1_MSG_DONE) + htx_set_eom(htx); return 1; + output_full: h1m_init_res(h1m); h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR); @@ -941,7 +938,7 @@ size_t h1_parse_msg_data(struct h1m *h1m, struct htx **dsthtx, total += sz; if (!h1m->curr_len) { h1m->state = H1_MSG_DONE; - (*dsthtx)->flags |= HTX_FL_EOM; + htx_set_eom(*dsthtx); } } else if (h1m->flags & H1_MF_CHNK) { @@ -953,7 +950,7 @@ size_t h1_parse_msg_data(struct h1m *h1m, struct htx **dsthtx, * body. Switch the message in DONE state */ h1m->state = H1_MSG_DONE; - (*dsthtx)->flags |= HTX_FL_EOM; + htx_set_eom(*dsthtx); } else { /* no content length, read till SHUTW */ @@ -1018,7 +1015,7 @@ int h1_parse_msg_tlrs(struct h1m *h1m, struct htx *dsthtx, goto error; h1m->state = H1_MSG_DONE; - dsthtx->flags |= HTX_FL_EOM; + htx_set_eom(dsthtx); end: return ret; diff --git a/src/h2.c b/src/h2.c index f0302211a..4a805fce2 100644 --- a/src/h2.c +++ b/src/h2.c @@ -485,8 +485,6 @@ int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *ms (*msgf & H2_MSGF_BODY_TUNNEL)) { /* Request without body or tunnel requested */ sl_flags |= HTX_SL_F_BODYLESS; - if (*msgf & H2_MSGF_BODY_TUNNEL) - htx->flags |= HTX_FL_EOM; } if (*msgf & H2_MSGF_EXT_CONNECT) { @@ -531,6 +529,9 @@ int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *ms if (!htx_add_endof(htx, HTX_BLK_EOH)) goto fail; + if (*msgf & H2_MSGF_BODY_TUNNEL) + htx_set_eom(htx); + /* proceed to scheme-based normalization on target-URI */ if (fields & H2_PHDR_FND_SCHM) http_scheme_based_normalize(htx); @@ -775,8 +776,6 @@ int h2_make_htx_response(struct http_hdr *list, struct htx *htx, unsigned int *m (*msgf & H2_MSGF_BODY_TUNNEL)) { /* Response without body or tunnel successfully established */ sl_flags |= HTX_SL_F_BODYLESS; - if (*msgf & H2_MSGF_BODY_TUNNEL) - htx->flags |= HTX_FL_EOM; } /* update the start line with last detected header info */ @@ -797,6 +796,9 @@ int h2_make_htx_response(struct http_hdr *list, struct htx *htx, unsigned int *m if (!htx_add_endof(htx, HTX_BLK_EOH)) goto fail; + if (*msgf & H2_MSGF_BODY_TUNNEL) + htx_set_eom(htx); + ret = 1; return ret; diff --git a/src/h3.c b/src/h3.c index 838a86151..aea4d7d30 100644 --- a/src/h3.c +++ b/src/h3.c @@ -1169,7 +1169,7 @@ static ssize_t h3_req_headers_to_htx(struct qcs *qcs, const struct buffer *buf, } if (fin) - htx->flags |= HTX_FL_EOM; + htx_set_eom(htx); htx_to_buf(htx, &htx_buf); htx = NULL; @@ -1450,7 +1450,7 @@ static ssize_t h3_resp_headers_to_htx(struct qcs *qcs, const struct buffer *buf, } if (fin) - htx->flags |= HTX_FL_EOM; + htx_set_eom(htx); /* Detect if an interim or final response was handled. */ if (sl->info.res.status >= 100 && sl->info.res.status < 200) { @@ -1635,7 +1635,7 @@ static ssize_t h3_trailers_to_htx(struct qcs *qcs, const struct buffer *buf, } if (fin) - htx->flags |= HTX_FL_EOM; + htx_set_eom(htx); out: /* HTX may be non NULL if error before previous htx_to_buf(). */ @@ -1711,7 +1711,7 @@ static ssize_t h3_data_to_htx(struct qcs *qcs, const struct buffer *buf, } if (fin && len == htx_sent) - htx->flags |= HTX_FL_EOM; + htx_set_eom(htx); out: if (appbuf) diff --git a/src/haload.c b/src/haload.c index e13e3cf77..fe12f5e7a 100644 --- a/src/haload.c +++ b/src/haload.c @@ -894,7 +894,7 @@ static int hldstream_build_http_req(struct hldstream *hs, struct ist path, int e goto err; if (eom) - htx->flags |= HTX_FL_EOM; + htx_set_eom(htx); htx_to_buf(htx, &hs->bo); leave: ret = 1; diff --git a/src/haterm.c b/src/haterm.c index cc3a9b2d9..654ab4c47 100644 --- a/src/haterm.c +++ b/src/haterm.c @@ -482,7 +482,7 @@ static int hstream_build_http_help_resp(struct hstream *hs) goto err; } - htx->flags |= HTX_FL_EOM; + htx_set_eom(htx); hs->flags |= HS_ST_HTTP_EOM_SENT; htx_to_buf(htx, buf); sl->info.res.status = 200; @@ -728,7 +728,7 @@ static int hstream_build_http_resp(struct hstream *hs) if (hs->to_write > 0) hs->to_write -= hstream_add_htx_data(hs, htx, hs->to_write); if (hs->to_write <= 0) { - htx->flags |= HTX_FL_EOM; + htx_set_eom(htx); hs->flags |= HS_ST_HTTP_EOM_SENT; } htx_to_buf(htx, buf); @@ -1060,7 +1060,7 @@ static struct task *process_hstream(struct task *t, void *context, unsigned int if (hs->to_write > 0) hs->to_write -= hstream_add_htx_data(hs, htx, hs->to_write); if (hs->to_write <= 0) { - htx->flags |= HTX_FL_EOM; + htx_set_eom(htx); hs->flags |= HS_ST_HTTP_EOM_SENT; } htx_to_buf(htx, &hs->res); diff --git a/src/hlua.c b/src/hlua.c index 99318b330..cb44e02f2 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -7888,7 +7888,7 @@ __LJMP static int hlua_http_msg_set_eom(lua_State *L) MAY_LJMP(check_args(L, 1, "set_eom")); msg = MAY_LJMP(hlua_checkhttpmsg(L, 1)); htx = htxbuf(&msg->chn->buf); - htx->flags |= HTX_FL_EOM; + htx_set_eom(htx); return 0; } @@ -8438,7 +8438,7 @@ __LJMP static int hlua_txn_forward_reply(lua_State *L, struct stream *s) (body_len && !htx_add_data_atonce(htx, ist2(body, body_len)))) goto fail; - htx->flags |= HTX_FL_EOM; + htx_set_eom(htx); /* Now, forward the response and terminate the transaction */ s->txn.http->status = code; @@ -11052,14 +11052,11 @@ void hlua_applet_http_fct(struct appctx *ctx) * sure the EOM flags will be handled by the endpoint. */ res_htx = htx_from_buf(outbuf); - if (htx_is_empty(res_htx)) { - if (!htx_add_endof(res_htx, HTX_BLK_EOT)) { - applet_have_more_data(ctx); - yield = 1; - goto out; - } + if (!htx_set_eom(res_htx)) { + applet_have_more_data(ctx); + yield = 1; + goto out; } - res_htx->flags |= HTX_FL_EOM; htx_to_buf(res_htx, outbuf); applet_set_eoi(ctx); applet_set_eos(ctx); diff --git a/src/hq_interop.c b/src/hq_interop.c index 4d2b4a80f..1eb4b6ee1 100644 --- a/src/hq_interop.c +++ b/src/hq_interop.c @@ -109,7 +109,7 @@ static ssize_t hq_interop_rcv_buf_req(struct qcs *qcs, struct buffer *b, int fin sl->info.req.meth = find_http_meth(istptr(meth), 3); htx_add_endof(htx, HTX_BLK_EOH); - htx->flags |= HTX_FL_EOM; + htx_set_eom(htx); htx_to_buf(htx, &htx_buf); hq_trace_req(meth, path, QMUX_EV_QCC_RECV, ist(TRC_LOC), __FUNCTION__, qcs, qcs->qcc); @@ -202,7 +202,7 @@ static ssize_t hq_interop_rcv_buf_res(struct qcs *qcs, struct buffer *b, int fin } if (fin && to_copy == htx_sent) - htx->flags |= HTX_FL_EOM; + htx_set_eom(htx); } out: diff --git a/src/http_ana.c b/src/http_ana.c index b4a57cb08..3ac9b5a90 100644 --- a/src/http_ana.c +++ b/src/http_ana.c @@ -2632,7 +2632,7 @@ int http_apply_redirect_rule(struct redirect_rule *rule, struct stream *s, struc if (!htx_add_endof(htx, HTX_BLK_EOH)) goto fail; - htx->flags |= HTX_FL_EOM; + htx_set_eom(htx); htx_to_buf(htx, &res->buf); if (!(s->flags & SF_ERR_MASK)) @@ -4485,7 +4485,7 @@ void http_perform_server_redirect(struct stream *s, struct stconn *sc) if (!htx_add_endof(htx, HTX_BLK_EOH)) goto fail; - htx->flags |= HTX_FL_EOM; + htx_set_eom(htx); htx_to_buf(htx, &res->buf); if (!(s->flags & SF_ERR_MASK)) @@ -4780,7 +4780,8 @@ int http_forward_proxy_resp(struct stream *s, int final) channel_auto_close(res); sc_schedule_abort(s->scb); s->scb->flags |= SC_FL_EOI; /* The response is terminated, add EOI */ - htxbuf(&res->buf)->flags |= HTX_FL_EOM; /* no more data are expected */ + if (!htx_is_empty(htx)) + htx_set_eom(htx); /* no more data are expected */ } else { /* Send ASAP informational messages. Rely on SC_FL_EOI for final @@ -4999,7 +5000,7 @@ int http_reply_to_htx(struct stream *s, struct htx *htx, struct http_reply *repl (body && b_data(body) && !htx_add_data_atonce(htx, ist2(b_head(body), b_data(body))))) goto fail; - htx->flags |= HTX_FL_EOM; + htx_set_eom(htx); } leave: diff --git a/src/http_client.c b/src/http_client.c index 96d55ee80..35341fd63 100644 --- a/src/http_client.c +++ b/src/http_client.c @@ -168,7 +168,7 @@ int httpclient_req_gen(struct httpclient *hc, const struct ist url, enum http_me /* If req.payload was set, does not set the end of stream which *MUST* * be set in the callback */ if (!hc->ops.req_payload) - htx->flags |= HTX_FL_EOM; + htx_set_eom(htx); htx_to_buf(htx, &hc->req.buf); @@ -236,17 +236,9 @@ int httpclient_req_xfer(struct httpclient *hc, struct ist src, int end) /* if we copied all the data and the end flag is set */ if ((istlen(src) == ret) && end) { - /* no more data are expected. If the HTX buffer is empty, be - * sure to add something (EOT block in this case) to have - * something to send. It is important to be sure the EOM flags - * will be handled by the endpoint. Because the message is - * empty, this should not fail. Otherwise it is an error - */ - if (htx_is_empty(htx)) { - if (!htx_add_endof(htx, HTX_BLK_EOT)) - goto end; - } - htx->flags |= HTX_FL_EOM; + /* no more data are expected */ + if (!htx_set_eom(htx)) + goto end; } htx_to_buf(htx, &hc->req.buf); diff --git a/src/http_htx.c b/src/http_htx.c index a0993f654..f00649539 100644 --- a/src/http_htx.c +++ b/src/http_htx.c @@ -1086,8 +1086,7 @@ int http_str_to_htx(struct buffer *buf, struct ist raw, char **errmsg) } ret += sent; } - - htx->flags |= HTX_FL_EOM; + htx_set_eom(htx); return 1; diff --git a/src/mux_fcgi.c b/src/mux_fcgi.c index 3c8f0d2e1..c9fa7dc83 100644 --- a/src/mux_fcgi.c +++ b/src/mux_fcgi.c @@ -3595,9 +3595,8 @@ static size_t fcgi_strm_parse_response(struct fcgi_strm *fstrm, struct buffer *b if (!(h1m->flags & H1_MF_XFER_LEN) && fstrm->state != FCGI_SS_ERROR && (fstrm->flags & FCGI_SF_ES_RCVD) && b_data(&fstrm->rxbuf) == total) { TRACE_DEVEL("end of data", FCGI_EV_RSP_DATA, fconn->conn, fstrm); - if (htx_is_empty(htx) && !htx_add_endof(htx, HTX_BLK_EOT)) + if (!htx_set_eom(htx)) break; - htx->flags |= HTX_FL_EOM; h1m->state = H1_MSG_DONE; TRACE_USER("H1 response fully rcvd", FCGI_EV_RSP_DATA|FCGI_EV_RSP_EOM, fconn->conn, fstrm, htx); } diff --git a/src/mux_h2.c b/src/mux_h2.c index af8f84b02..ae6eb00a9 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -6421,7 +6421,7 @@ next_frame: goto fail; } /* no more data are expected for this message */ - htx->flags |= HTX_FL_EOM; + htx_set_eom(htx); *flags |= H2_SF_ES_RCVD; } diff --git a/src/stats-html.c b/src/stats-html.c index ae256fb02..069b964b4 100644 --- a/src/stats-html.c +++ b/src/stats-html.c @@ -2071,18 +2071,11 @@ static void http_stats_io_handler(struct appctx *appctx) } if (appctx->st0 == STAT_HTTP_DONE) { - /* no more data are expected. If the response buffer is empty, - * be sure to add something (EOT block in this case) to have - * something to send. It is important to be sure the EOM flags - * will be handled by the endpoint. - */ - if (htx_is_empty(res_htx)) { - if (!htx_add_endof(res_htx, HTX_BLK_EOT)) { - applet_fl_set(appctx, APPCTX_FL_OUTBLK_FULL); - goto out; - } + /* no more data are expected */ + if (!htx_set_eom(res_htx)) { + applet_fl_set(appctx, APPCTX_FL_OUTBLK_FULL); + goto out; } - res_htx->flags |= HTX_FL_EOM; applet_set_eoi(appctx); se_fl_clr(appctx->sedesc, SE_FL_MAY_FASTFWD_PROD); applet_fl_clr(appctx, APPCTX_FL_FASTFWD); diff --git a/src/tcpcheck.c b/src/tcpcheck.c index 5dcd8707a..9ca6c42d6 100644 --- a/src/tcpcheck.c +++ b/src/tcpcheck.c @@ -1831,7 +1831,7 @@ enum tcpcheck_eval_ret tcpcheck_eval_send(struct check *check, struct tcpcheck_r goto error_htx; /* no more data are expected */ - htx->flags |= HTX_FL_EOM; + htx_set_eom(htx); htx_to_buf(htx, &check->bo); break; }