]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: http-fetch: Add a sample to retrieve the server status code
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 27 Nov 2023 17:12:13 +0000 (18:12 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 29 Nov 2023 10:11:12 +0000 (11:11 +0100)
The code returned by the "status" sample fetch is the one in the HTTP
response at the moment the sample is evaluated. It may be the status code in
the server response or the one of the HAProxy reply in case of error, deny,
redirect...

However, it could be handy to retrieve the status code returned by the
server, when a HTTP response was really received from it. It is the purpose
of the "server_status" sample fetch. The server status code itself is stored
in the HTTP txn.

doc/configuration.txt
include/haproxy/http_ana-t.h
src/http_ana.c
src/http_fetch.c

index 8b7f4aa19b127351b3ce0d4f3d650f5aa844c943..76647e5e3ce9bf22753ca06b04f69391170ed082 100644 (file)
@@ -22822,6 +22822,10 @@ resp_ver : string (deprecated)
   ACL derivatives :
     resp.ver : exact string match
 
+server_status : integer
+  Return an integer containing the HTTP status code as received from the
+  server. If no response was received from the server, the sample fetch fails.
+
 set-cookie([<name>]) : string (deprecated)
   This extracts the last occurrence of the cookie name <name> on a "Set-Cookie"
   header line from the response and uses the corresponding value to match. This
index 41887a995c9dd0bfa3a362e0ef6ea8b58803e52b..5b7342f4d5f52cf161501e3e7612f5f3b48eb807 100644 (file)
@@ -239,7 +239,8 @@ struct http_txn {
        unsigned int flags;             /* transaction flags */
        enum http_meth_t meth;          /* HTTP method */
        /* 1 unused byte here */
-       short status;                   /* HTTP status from the server, negative if from proxy */
+       short status;                   /* HTTP status sent to the client, negative if not set */
+       short server_status;            /* HTTP status received from the server, negative if not received */
        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  */
index 37034ad2f14907d8877e246b3a379f0f4fa9da3b..bbf01ff85d8173e073ba8181a7be3a4d92fb1732 100644 (file)
@@ -1429,7 +1429,7 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit)
        }
 
        /* 1: get the status code and the version. Also set HTTP flags */
-       txn->status = sl->info.res.status;
+       txn->server_status = txn->status = sl->info.res.status;
        if (sl->flags & HTX_SL_F_VER_11)
                 msg->flags |= HTTP_MSGF_VER_11;
        if (sl->flags & HTX_SL_F_XFER_LEN) {
@@ -1488,7 +1488,7 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit)
                htx->first = channel_htx_fwd_headers(rep, htx);
                msg->msg_state = HTTP_MSG_RPBEFORE;
                msg->flags = 0;
-               txn->status = 0;
+               txn->server_status = txn->status = 0;
                s->logs.t_data = -1; /* was not a response yet */
                s->scf->flags |= SC_FL_SND_ASAP; /* Send ASAP informational messages */
                goto next_one;
@@ -5036,6 +5036,7 @@ struct http_txn *http_create_txn(struct stream *s)
        txn->meth = HTTP_METH_OTHER;
        txn->flags = ((sc && sc_ep_test(sc, SE_FL_NOT_FIRST)) ? TX_NOT_FIRST : 0);
        txn->status = -1;
+       txn->server_status = -1;
        txn->http_reply = NULL;
        txn->l7_buffer = BUF_NULL;
        write_u32(txn->cache_hash, 0);
index f5ff9f304f5b9d4f31c1e5dc26a88a87f4a2deda..38b1e0b0856b62e4ad29d95307e3d267df41f3f8 100644 (file)
@@ -311,8 +311,12 @@ struct htx *smp_prefetch_htx(struct sample *smp, struct channel *chn, struct che
                        if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
                                s->flags |= SF_REDIRECTABLE;
                }
-               else if (txn->status == -1)
-                       txn->status = sl->info.res.status;
+               else {
+                       if (txn->status == -1)
+                               txn->status = sl->info.res.status;
+                       if (!(htx->flags & HTX_FL_PROXY_RESP) && txn->server_status == -1)
+                               txn->server_status = sl->info.res.status;
+               }
                if (sl->flags & HTX_SL_F_VER_11)
                        msg->flags |= HTTP_MSGF_VER_11;
        }
@@ -441,6 +445,28 @@ static int smp_fetch_stcode(const struct arg *args, struct sample *smp, const ch
        return 1;
 }
 
+/* It returns the server status code */
+static int smp_fetch_srv_status(const struct arg *args, struct sample *smp, const char *kw, void *private)
+{
+       struct http_txn *txn;
+
+       txn = (smp->strm ? smp->strm->txn : NULL);
+       if (!txn)
+               return 0;
+
+       if (txn->server_status == -1) {
+               struct channel *chn = SMP_RES_CHN(smp);
+               struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
+
+               if (!htx)
+                       return 0;
+       }
+
+       smp->data.type = SMP_T_SINT;
+       smp->data.u.sint = txn->server_status;
+       return 1;
+}
+
 static int smp_fetch_uniqueid(const struct arg *args, struct sample *smp, const char *kw, void *private)
 {
        struct ist unique_id;
@@ -2298,6 +2324,8 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
        { "res.hdr_names",      smp_fetch_hdr_names,          ARG1(0,STR),      NULL,    SMP_T_STR,  SMP_USE_HRSHV },
        { "res.hdr_val",        smp_fetch_hdr_val,            ARG2(0,STR,SINT), val_hdr, SMP_T_SINT, SMP_USE_HRSHV },
 
+       { "server_status",      smp_fetch_srv_status,         0,                NULL,    SMP_T_SINT, SMP_USE_HRSHP },
+
        /* scook is valid only on the response and is used for ACL compatibility */
        { "scook",              smp_fetch_cookie,             ARG1(0,STR),      NULL,    SMP_T_STR,  SMP_USE_HRSHV },
        { "scook_cnt",          smp_fetch_cookie_cnt,         ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_HRSHV },