diff --git a/doc/configuration.txt b/doc/configuration.txt index 8b7f4aa19..76647e5e3 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 41887a995..5b7342f4d 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 37034ad2f..bbf01ff85 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 f5ff9f304..38b1e0b08 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 },