From: Christopher Faulet Date: Mon, 27 Nov 2023 17:12:13 +0000 (+0100) Subject: MINOR: http-fetch: Add a sample to retrieve the server status code X-Git-Tag: v2.9-dev12~31 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b2f82b2b51ffa90ae0463f5fb2fe60b24d856bb3;p=thirdparty%2Fhaproxy.git MINOR: http-fetch: Add a sample to retrieve the server status code 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. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index 8b7f4aa19b..76647e5e3c 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -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([]) : string (deprecated) This extracts the last occurrence of the cookie name on a "Set-Cookie" header line from the response and uses the corresponding value to match. This diff --git a/include/haproxy/http_ana-t.h b/include/haproxy/http_ana-t.h index 41887a995c..5b7342f4d5 100644 --- a/include/haproxy/http_ana-t.h +++ b/include/haproxy/http_ana-t.h @@ -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 */ diff --git a/src/http_ana.c b/src/http_ana.c index 37034ad2f1..bbf01ff85d 100644 --- a/src/http_ana.c +++ b/src/http_ana.c @@ -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); diff --git a/src/http_fetch.c b/src/http_fetch.c index f5ff9f304f..38b1e0b085 100644 --- a/src/http_fetch.c +++ b/src/http_fetch.c @@ -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 },