]> git.kaiwu.me - haproxy.git/commitdiff
MAJOR: htx: Use htx_set_eom() instead of setting HTX_FL_EOM by hand
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 8 Jul 2026 14:13:24 +0000 (16:13 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 24 Jul 2026 09:58:25 +0000 (11:58 +0200)
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.

17 files changed:
addons/promex/service-prometheus.c
include/haproxy/htx.h
src/cache.c
src/h1_htx.c
src/h2.c
src/h3.c
src/haload.c
src/haterm.c
src/hlua.c
src/hq_interop.c
src/http_ana.c
src/http_client.c
src/http_htx.c
src/mux_fcgi.c
src/mux_h2.c
src/stats-html.c
src/tcpcheck.c

index d655c4345017153dc5be569f3ec193ade5a99130..638774f306d21e35d2da2d7ec49d7808f11b2030 100644 (file)
@@ -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;
index c68e695e8d9505ff987168a19165c9e48f9ed3c4..74b3ed2ee1baf4df495b4d0d5dabd19eea2ba7ed 100644 (file)
@@ -837,10 +837,11 @@ static inline int htx_expect_more(const struct htx *htx)
        return !(htx->flags & HTX_FL_EOM);
 }
 
-/* Set EOM flag in <htx>. 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 <htx>. 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.
  */
index e20d8a5f0da7ec9b7f064ced75cb814b75586e00..1a1b6a46f92b14083cae3a88e6102ccf2c74ffaf 100644 (file)
@@ -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);
index 5b112d2f88a38987d7d1ff8e40b56032abe774dd..e5a340912e6a9bbf0c17dbc040778e1eee4159c3 100644 (file)
@@ -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;
index f0302211a6b9974a8c38318da6e13bf2421f8d1e..4a805fce2ee2b8c45902b60787cb9ced7e096b68 100644 (file)
--- 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;
 
index 838a861513edd4306020db5c1cb3a0801d6c461c..aea4d7d3034013acf59f84f02efadf50647d2479 100644 (file)
--- 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)
index e13e3cf777253eb31d2b9d8053bccd9cf6746e92..fe12f5e7a697a56acf008ba77f3ad8d0e8fd6110 100644 (file)
@@ -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;
index cc3a9b2d903db2c6e4bafc36e8b509a286cd817f..654ab4c4748284199bc7d726ebe67b1e96a8992b 100644 (file)
@@ -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);
index 99318b3301357a3a030cf120a1f7807c26896161..cb44e02f25e0710cbe0279e2cf3fdc645e44e93a 100644 (file)
@@ -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);
index 4d2b4a80f042c393339a1b5e9927efa582cf6fff..1eb4b6ee1d73d7f5ef4f8461edc9fb6275f95cc1 100644 (file)
@@ -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:
index b4a57cb082267730cf29f44742ed46059ad97ee0..3ac9b5a90a2b2299d54fafe31a034c903fc979af 100644 (file)
@@ -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:
index 96d55ee803919b90c4f1c333fcb6b16eeef840bb..35341fd637359fb54b3ccfa730245d810a284310 100644 (file)
@@ -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);
 
index a0993f654965f31f65258f899ce12c204e983d11..f006495397d8e2a6602f258b7c6258f1823d3c49 100644 (file)
@@ -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;
 
index 3c8f0d2e1deeb688a2716164b71fd7ce8afd23bb..c9fa7dc830b29b16689d69a852cff0895b60ec6e 100644 (file)
@@ -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);
                        }
index af8f84b02d4ca6da125addde3c5e7195e8312de2..ae6eb00a94d2e68985024e97b4b539036ef49f92 100644 (file)
@@ -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;
        }
 
index ae256fb02dc5c64a5cd593b433a9a02abe117ef7..069b964b4d8823c2ae5c2abd1821716d0c50e6ec 100644 (file)
@@ -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);
index 5dcd8707aaa9711abfce31112ee811169c237a01..9ca6c42d6703cd1b2bf776b1521b70d7449456c9 100644 (file)
@@ -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;
        }