]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: stream-int/txn: Move buffer for L7 retries in the HTTP transaction
authorChristopher Faulet <cfaulet@haproxy.com>
Tue, 29 Mar 2022 13:23:40 +0000 (15:23 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 13 Apr 2022 13:10:14 +0000 (15:10 +0200)
The L7 retries only concerns the stream when a server connection is
established. Thus instead of storing the L7 buffer into the
stream-interface, it may be moved to the stream. And because it is only
available for HTTP streams, it may be moved in the HTTP transaction.

Associated flags are also moved into the HTTP transaction.

dev/flags/flags.c
include/haproxy/http_ana-t.h
include/haproxy/stream_interface-t.h
include/haproxy/stream_interface.h
src/http_act.c
src/http_ana.c
src/stream.c
src/stream_interface.c

index 50f48b1fb85533cf214552ffd7505a7ec5e95288..02064b39eaf6bdd8092255c047d12e4744ab2edc 100644 (file)
@@ -279,8 +279,6 @@ void show_si_flags(unsigned int f)
        SHOW_FLAG(f, SI_FL_RXBLK_SHUT);
        SHOW_FLAG(f, SI_FL_RXBLK_CONN);
        SHOW_FLAG(f, SI_FL_RX_WAIT_EP);
-       SHOW_FLAG(f, SI_FL_L7_RETRY);
-       SHOW_FLAG(f, SI_FL_D_L7_RETRY);
        SHOW_FLAG(f, SI_FL_ADDR_FROM_SET);
        SHOW_FLAG(f, SI_FL_ADDR_TO_SET);
 
@@ -332,6 +330,8 @@ void show_txn_flags(unsigned int f)
                return;
        }
 
+       SHOW_FLAG(f, TX_L7_RETRY);
+       SHOW_FLAG(f, TX_D_L7_RETRY);
        SHOW_FLAG(f, TX_NOT_FIRST);
        SHOW_FLAG(f, TX_USE_PX_CONN);
        SHOW_FLAG(f, TX_CACHE_HAS_SEC_KEY);
index 96845a45b26ee20db5aaea8e45943fc991329887..b267ebebda4cda234411ffc741d5c7a10eccbb68 100644 (file)
@@ -71,6 +71,8 @@
 /* used only for keep-alive purposes, to indicate we're on a second transaction */
 #define TX_NOT_FIRST   0x00040000      /* the transaction is not the first one */
 
+#define TX_L7_RETRY     0x000800000     /* The transaction may attempt L7 retries */
+#define TX_D_L7_RETRY   0x001000000     /* Disable L7 retries on this transaction, even if configured to do it */
 /*
  * HTTP message status flags (msg->flags)
  */
@@ -184,7 +186,7 @@ struct http_txn {
        /* 1 unused byte here */
        short status;                   /* HTTP status from the server, negative if from proxy */
        struct http_reply *http_reply;  /* The HTTP reply to use as reply */
-
+       struct buffer l7_buffer;        /* To store the data, in case we have to retry */
        char cache_hash[20];               /* Store the cache hash  */
        char cache_secondary_hash[HTTP_CACHE_SEC_KEY_LEN]; /* Optional cache secondary key. */
        char *uri;                      /* first line if log needed, NULL otherwise */
index a6e7983600c10d5fb0d97a02e73f514badd06928..2e6ef39774ba8253d33457ee3b9c71a4ac7742d6 100644 (file)
@@ -104,8 +104,7 @@ enum {
        SI_FL_RXBLK_CONN = 0x00100000,  /* other side is not connected */
        SI_FL_RXBLK_ANY  = 0x001F0000,  /* any of the RXBLK flags above */
        SI_FL_RX_WAIT_EP = 0x00200000,  /* stream-int waits for more data from the end point */
-       SI_FL_L7_RETRY   = 0x01000000,  /* The stream interface may attempt L7 retries */
-       SI_FL_D_L7_RETRY = 0x02000000,  /* Disable L7 retries on this stream interface, even if configured to do it */
+       /* unused: 0x01000000, 0x02000000 */
 
        SI_FL_ADDR_FROM_SET = 0x04000000, /* source address is set */
        SI_FL_ADDR_TO_SET   = 0x08000000  /* destination address is set */
@@ -140,7 +139,6 @@ struct stream_interface {
 
        unsigned int hcto;      /* half-closed timeout (0 = unset) */
        struct wait_event wait_event; /* We're in a wait list */
-       struct buffer l7_buffer; /* To store the data, in case we have to retry */
 };
 
 /* operations available on a stream-interface */
index 89ebcda3831a3705bb9b7e52632132ae7f4abd6a..60efe1de357419612751a832d2ea69099a5951f4 100644 (file)
@@ -116,7 +116,6 @@ static inline int si_init(struct stream_interface *si)
        si->cs             = NULL;
        si->state          = si->prev_state = SI_ST_INI;
        si->ops            = &si_embedded_ops;
-       si->l7_buffer      = BUF_NULL;
        si->wait_event.tasklet = tasklet_new();
        if (!si->wait_event.tasklet)
                return -1;
index eebc1884f654ee1a19a6557710f2169c9320a16f..f35fadfb56b83ee1694924adfc5694017500a5ac 100644 (file)
@@ -752,19 +752,17 @@ static enum act_parse_ret parse_http_action_reject(const char **args, int *orig_
 /* This function executes the "disable-l7-retry" HTTP action.
  * It disables L7 retries (all retry except for a connection failure). This
  * can be useful for example to avoid retrying on POST requests.
- * It just removes the L7 retry flag on the stream_interface, and always
+ * It just removes the L7 retry flag on the HTTP transaction, and always
  * return ACT_RET_CONT;
  */
 static enum act_return http_req_disable_l7_retry(struct act_rule *rule, struct proxy *px,
                                           struct session *sess, struct stream *s, int flags)
 {
-       struct stream_interface *si = cs_si(s->csb);
-
-       /* In theory, the SI_FL_L7_RETRY flags isn't set at this point, but
+       /* In theory, the TX_L7_RETRY flags isn't set at this point, but
         * let's be future-proof and remove it anyway.
         */
-       si->flags &= ~SI_FL_L7_RETRY;
-       si->flags |= SI_FL_D_L7_RETRY;
+       s->txn->flags &= ~TX_L7_RETRY;
+       s->txn->flags |= TX_D_L7_RETRY;
        return ACT_RET_CONT;
 }
 
index 05b62fe02053c8788b7e5e6d04be9a1034227bf7..4ce49bb671945011d03daa8775ba60e39eaa1d0a 100644 (file)
@@ -987,7 +987,7 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
                 * was a write error, we may recover.
                 */
                if (!(req->flags & (CF_READ_ERROR | CF_READ_TIMEOUT)) &&
-                   (cs_si(s->csb)->flags & SI_FL_L7_RETRY)) {
+                   (txn->flags & TX_L7_RETRY)) {
                        DBG_TRACE_DEVEL("leaving on L7 retry",
                                        STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA|STRM_EV_HTTP_ERR, s, txn);
                        return 0;
@@ -1264,9 +1264,9 @@ static __inline int do_l7_retry(struct stream *s, struct stream_interface *si)
        b_free(&req->buf);
        /* Swap the L7 buffer with the channel buffer */
        /* We know we stored the co_data as b_data, so get it there */
-       co_data = b_data(&si->l7_buffer);
-       b_set_data(&si->l7_buffer, b_size(&si->l7_buffer));
-       b_xfer(&req->buf, &si->l7_buffer, b_data(&si->l7_buffer));
+       co_data = b_data(&s->txn->l7_buffer);
+       b_set_data(&s->txn->l7_buffer, b_size(&s->txn->l7_buffer));
+       b_xfer(&req->buf, &s->txn->l7_buffer, b_data(&s->txn->l7_buffer));
        co_set_data(req, co_data);
 
        DBG_TRACE_DEVEL("perform a L7 retry", STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA, s, s->txn);
@@ -1330,7 +1330,7 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit)
                        struct connection *conn = cs_conn(s->csb);
 
                        /* Perform a L7 retry because server refuses the early data. */
-                       if ((si_b->flags & SI_FL_L7_RETRY) &&
+                       if ((txn->flags & TX_L7_RETRY) &&
                            (s->be->retry_type & PR_RE_EARLY_ERROR) &&
                            conn && conn->err_code == CO_ER_SSL_EARLY_FAILED &&
                            do_l7_retry(s, si_b) == 0) {
@@ -1370,7 +1370,7 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit)
 
                /* 2: read timeout : return a 504 to the client. */
                else if (rep->flags & CF_READ_TIMEOUT) {
-                       if ((si_b->flags & SI_FL_L7_RETRY) &&
+                       if ((txn->flags & TX_L7_RETRY) &&
                            (s->be->retry_type & PR_RE_TIMEOUT)) {
                                if (co_data(rep) || do_l7_retry(s, si_b) == 0) {
                                        DBG_TRACE_DEVEL("leaving on L7 retry",
@@ -1423,7 +1423,7 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit)
 
                /* 4: close from server, capture the response if the server has started to respond */
                else if (rep->flags & CF_SHUTR) {
-                       if ((si_b->flags & SI_FL_L7_RETRY) &&
+                       if ((txn->flags & TX_L7_RETRY) &&
                            (s->be->retry_type & PR_RE_DISCONNECTED)) {
                                if (co_data(rep) || do_l7_retry(s, si_b) == 0) {
                                        DBG_TRACE_DEVEL("leaving on L7 retry",
@@ -1491,7 +1491,7 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit)
        sl = http_get_stline(htx);
 
        /* Perform a L7 retry because of the status code */
-       if ((si_b->flags & SI_FL_L7_RETRY) &&
+       if ((txn->flags & TX_L7_RETRY) &&
            l7_status_match(s->be, sl->info.res.status) &&
            do_l7_retry(s, si_b) == 0) {
                DBG_TRACE_DEVEL("leaving on L7 retry", STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA, s, txn);
@@ -1499,7 +1499,7 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit)
        }
 
        /* Now, L7 buffer is useless, it can be released */
-       b_free(&(cs_si(s->csb)->l7_buffer));
+       b_free(&txn->l7_buffer);
 
        msg->msg_state = HTTP_MSG_BODY;
 
@@ -1720,7 +1720,7 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit)
                health_adjust(__objt_server(s->target), HANA_STATUS_HTTP_HDRRSP);
        }
        if ((s->be->retry_type & PR_RE_JUNK_REQUEST) &&
-           (si_b->flags & SI_FL_L7_RETRY) &&
+           (txn->flags & TX_L7_RETRY) &&
            do_l7_retry(s, si_b) == 0) {
                DBG_TRACE_DEVEL("leaving on L7 retry",
                                STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA, s, txn);
@@ -5139,6 +5139,7 @@ struct http_txn *http_create_txn(struct stream *s)
        txn->flags = ((cs && cs->endp->flags & CS_EP_NOT_FIRST) ? TX_NOT_FIRST : 0);
        txn->status = -1;
        txn->http_reply = NULL;
+       txn->l7_buffer = BUF_NULL;
        write_u32(txn->cache_hash, 0);
 
        txn->cookie_first_date = 0;
@@ -5183,6 +5184,8 @@ void http_destroy_txn(struct stream *s)
        if (!LIST_ISEMPTY(&s->vars_reqres.head))
                vars_prune(&s->vars_reqres, s->sess, s);
 
+       b_free(&txn->l7_buffer);
+
        pool_free(pool_head_http_txn, txn);
        s->txn = NULL;
 }
index 833be0e1bbcb3cfc9f0a31a00a6575ef2abd85bb..fe1e2c299b5e8e1903b748cd2060cc7acf232021 100644 (file)
@@ -2163,8 +2163,8 @@ struct task *process_stream(struct task *t, void *context, unsigned int state)
                                si_b->conn_retries = s->be->conn_retries;
                                if ((s->be->retry_type &~ PR_RE_CONN_FAILED) &&
                                    (s->be->mode == PR_MODE_HTTP) &&
-                                   !(si_b->flags & SI_FL_D_L7_RETRY))
-                                       si_b->flags |= SI_FL_L7_RETRY;
+                                   !(s->txn->flags & TX_D_L7_RETRY))
+                                       s->txn->flags |= TX_L7_RETRY;
                        }
                }
                else {
index 194c5ff11ae44efe61c7641020c62bb062a10625..1e28a8fc04f4c43e43ed825232abaafbd53b45f1 100644 (file)
@@ -124,7 +124,6 @@ void si_free(struct stream_interface *si)
        if (!si)
                return;
 
-       b_free(&si->l7_buffer);
        tasklet_free(si->wait_event.tasklet);
        sockaddr_free(&si->src);
        sockaddr_free(&si->dst);
@@ -703,6 +702,7 @@ static int si_cs_send(struct conn_stream *cs)
 {
        struct connection *conn = __cs_conn(cs);
        struct stream_interface *si = cs_si(cs);
+       struct stream *s = si_strm(si);
        struct channel *oc = si_oc(si);
        int ret;
        int did_send = 0;
@@ -778,8 +778,7 @@ static int si_cs_send(struct conn_stream *cs)
                if (oc->flags & CF_STREAMER)
                        send_flag |= CO_SFL_STREAMER;
 
-               if ((si->flags & SI_FL_L7_RETRY) && !b_data(&si->l7_buffer)) {
-                       struct stream *s = si_strm(si);
+               if (s->txn && s->txn->flags & TX_L7_RETRY && !b_data(&s->txn->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
@@ -789,17 +788,17 @@ static int si_cs_send(struct conn_stream *cs)
                         * disable the l7 retries by setting
                         * l7_conn_retries to 0.
                         */
-                       if (!s->txn || (s->txn->req.msg_state != HTTP_MSG_DONE))
-                               si->flags &= ~SI_FL_L7_RETRY;
+                       if (s->txn->req.msg_state != HTTP_MSG_DONE)
+                               s->txn->flags &= ~TX_L7_RETRY;
                        else {
-                               if (b_alloc(&si->l7_buffer) == NULL)
-                                       si->flags &= ~SI_FL_L7_RETRY;
+                               if (b_alloc(&s->txn->l7_buffer) == NULL)
+                                       s->txn->flags &= ~TX_L7_RETRY;
                                else {
-                                       memcpy(b_orig(&si->l7_buffer),
+                                       memcpy(b_orig(&s->txn->l7_buffer),
                                               b_orig(&oc->buf),
                                               b_size(&oc->buf));
-                                       si->l7_buffer.head = co_data(oc);
-                                       b_add(&si->l7_buffer, co_data(oc));
+                                       s->txn->l7_buffer.head = co_data(oc);
+                                       b_add(&s->txn->l7_buffer, co_data(oc));
                                }
 
                        }