]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: stream: Add flags to identify the stream tansaction when allocated
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 20 Apr 2026 16:33:36 +0000 (18:33 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 22 Apr 2026 13:19:12 +0000 (15:19 +0200)
To be able to deal with different types of transaction for a stream, new
stream flags was added to know the transaction type when allocated. For now
only HTTP transactions can be allocated, so only SF_TXN_HTTP was
introduced. The mask SF_TXN_MASK must be used to get the transaction type.

The transaction type is set when it is allocated and removed when it is
destroyed.

include/haproxy/stream-t.h
src/debug.c
src/http_ana.c
src/log.c
src/stconn.c
src/stream.c

index ecd31caaeddd8c58d82bc86d80ab1e565c3e5c20..7162dceadc1009cd59407d9a4de7b31918b3af75 100644 (file)
 #define SF_BC_MARK      0x01000000     /* need to set specific mark on backend/srv conn upon connect */
 #define SF_BC_TOS       0x02000000     /* need to set specific tos on backend/srv conn upon connect */
 #define SF_RULE_FYIELD  0x04000000      /* s->current_rule set because of forced yield */
+/* unused: 0x08000000 */
+#define SF_TXN_NONE     0x00000000      /* No transaction allocated */
+#define SF_TXN_HTTP     0x10000000      /* HTTP transaction allocated */
+#define SF_TXN_MASK     0x10000000      /* mask to get the transaction type */
 
 /* This function is used to report flags in debugging tools. Please reflect
  * below any single-bit flag addition above in the same order via the
index ce31711d3c57bb070d7965cd26415e9ea64ea9d5..50a8856dcbde28f346e6f4a792d9ed26d2b5e297 100644 (file)
@@ -1401,7 +1401,8 @@ static int debug_parse_cli_stream(char **args, char *payload, struct appctx *app
                } else if (isteq(name, ist("strm.x"))) {
                        ptr = (!s || !may_access(s)) ? NULL : &s->conn_exp; size = sizeof(s->conn_exp);
                } else if (isteq(name, ist("txn.f"))) {
-                       ptr = (!s || !may_access(s)) ? NULL : &s->txn.http->flags; size = sizeof(s->txn.http->flags);
+                       ptr = (!s || !may_access(s) || (s->flags & SF_TXN_MASK) != SF_TXN_HTTP) ? NULL : &s->txn.http->flags;
+                       size = sizeof(s->txn.http->flags);
                } else if (isteq(name, ist("req.f"))) {
                        ptr = (!s || !may_access(s)) ? NULL : &s->req.flags; size = sizeof(s->req.flags);
                } else if (isteq(name, ist("res.f"))) {
index aea92a9f7d0558af31e1cf31f1ad1fe3a3d32201..9087dfa9e2792dcb0e6320285449d014a5858746 100644 (file)
@@ -5290,6 +5290,9 @@ struct http_txn *http_create_txn(struct stream *s)
        struct http_txn *txn;
        struct stconn *sc = s->scf;
 
+       if ((s->flags & SF_TXN_MASK) != SF_TXN_NONE)
+               return NULL;
+
        txn = pool_alloc(pool_head_http_txn);
        if (!txn)
                return NULL;
@@ -5318,6 +5321,8 @@ struct http_txn *http_create_txn(struct stream *s)
 
        txn->auth.method = HTTP_AUTH_UNKNOWN;
 
+       s->flags |= SF_TXN_HTTP;
+
        /* here we don't want to re-initialize s->vars_txn and s->vars_reqres
         * variable lists, because they were already initialized upon stream
         * creation in stream_new(), and thus may already contain some variables
@@ -5349,6 +5354,7 @@ void http_destroy_txn(struct stream *s)
 
        pool_free(pool_head_http_txn, txn);
        s->txn.http = NULL;
+       s->flags &= ~SF_TXN_MASK;
 }
 
 
index be06ad0601fec8f98b7d5b22084f4c87d3b2704e..ad435dddaff2e96ef9555fd9bc65872c880a3c02 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -3959,7 +3959,7 @@ size_t sess_build_logline_orig(struct session *sess, struct stream *s,
 
        if (likely(s)) {
                be = s->be;
-               txn = s->txn.http;
+               txn = (((s->flags & SF_TXN_MASK) == SF_TXN_HTTP) ? s->txn.http : NULL);
                be_conn = sc_conn(s->scb);
                status = (txn ? txn->status : 0);
                s_flags = s->flags;
index 2941c2d1e285f8de62fb368e72b6774b2183ce6a..c2f96a198f554404e36c8dbab82deb8a2e84cf97 100644 (file)
@@ -1488,7 +1488,7 @@ int sc_conn_send(struct stconn *sc)
                if (oc->flags & CF_STREAMER)
                        send_flag |= CO_SFL_STREAMER;
 
-               if (s->txn.http && s->txn.http->flags & TX_L7_RETRY && !b_data(&s->txn.http->l7_buffer)) {
+               if ((s->flags & SF_TXN_MASK) == SF_TXN_HTTP && (s->txn.http->flags & TX_L7_RETRY) && !b_data(&s->txn.http->l7_buffer)) {
                        /* If we want to be able to do L7 retries, copy
                         * the data we're about to send, so that we are able
                         * to resend them if needed
index bb88c6288f55985c78e52fc4f02dec982ac150e2..cd271ff046fd62ccf98e6c9379bbeec027b4f6fe 100644 (file)
@@ -683,7 +683,7 @@ void stream_free(struct stream *s)
        hlua_ctx_destroy(s->hlua[1]);
        s->hlua[0] = s->hlua[1] = NULL;
 
-       if (s->txn.http)
+       if ((s->flags & SF_TXN_MASK) == SF_TXN_HTTP)
                http_destroy_txn(s);
 
        /* ensure the client-side transport layer is destroyed */
@@ -1299,7 +1299,7 @@ static int process_switching_rules(struct stream *s, struct channel *req, int an
        if (!(s->flags & SF_FINST_MASK))
                s->flags |= SF_FINST_R;
 
-       if (s->txn.http)
+       if ((s->flags & SF_TXN_MASK) == SF_TXN_HTTP)
                s->txn.http->status = 500;
        s->req.analysers &= AN_REQ_FLT_END;
        s->req.analyse_exp = TICK_ETERNITY;
@@ -1594,7 +1594,7 @@ int stream_set_http_mode(struct stream *s, const struct mux_proto_list *mux_prot
 
        s->req.analysers |= AN_REQ_WAIT_HTTP|AN_REQ_HTTP_PROCESS_FE;
 
-       if (unlikely(!s->txn.http && !http_create_txn(s)))
+       if (unlikely((s->flags & SF_TXN_MASK) != SF_TXN_HTTP && !http_create_txn(s)))
                return 0;
 
        conn = sc_conn(sc);
@@ -1913,7 +1913,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state)
        }
 
        /* this data may be no longer valid, clear it */
-       if (s->txn.http)
+       if ((s->flags & SF_TXN_MASK) == SF_TXN_HTTP)
                memset(&s->txn.http->auth, 0, sizeof(s->txn.http->auth));
 
        /* 1a: Check for low level timeouts if needed. We just set a flag on
@@ -2774,7 +2774,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state)
 
                stream_process_counters(s);
 
-               if (s->txn.http && s->txn.http->status) {
+               if ((s->flags & SF_TXN_MASK) == SF_TXN_HTTP && s->txn.http->status) {
                        int n;
 
                        n = s->txn.http->status / 100;
@@ -3627,7 +3627,7 @@ static void __strm_dump_to_buffer(struct buffer *buf, const struct show_sess_ctx
                      " age=%s)\n",
                      human_time(ns_to_sec(now_ns) - ns_to_sec(request_ts), 1));
 
-       if (strm->txn.http) {
+       if ((strm->flags & SF_TXN_MASK) == SF_TXN_HTTP) {
                chunk_appendf(buf,
                      "%s  txn=%p flags=0x%x meth=%d status=%d req.st=%s rsp.st=%s req.f=0x%02x rsp.f=0x%02x", pfx,
                      strm->txn.http, strm->txn.http->flags,
@@ -4237,7 +4237,9 @@ static int cli_io_handler_dump_sess(struct appctx *appctx)
                if (task_in_rq(curr_strm->task))
                        chunk_appendf(&trash, " run(nice=%d)", curr_strm->task->nice);
 
-               if ((ctx->flags & CLI_SHOWSESS_F_DUMP_URI) && curr_strm->txn.http && curr_strm->txn.http->uri)
+               if ((ctx->flags & CLI_SHOWSESS_F_DUMP_URI) &&
+                   (curr_strm->flags & SF_TXN_MASK) == SF_TXN_HTTP &&
+                   curr_strm->txn.http->uri)
                        chunk_appendf(&trash, " uri=\"%s\"",
                                      HA_ANON_CLI(curr_strm->txn.http->uri));