From 2a5da31ccef239e21d17ec34430fdc6b51b9cc67 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Tue, 19 Nov 2024 16:33:55 +0100 Subject: [PATCH] BUG/MINOR: http-ana: Adjust the server status before the L7 retries The server status must be adjusted, if necessary, at each retry. It is properly performed when "obersve layer4" directive is set. But for the layer 7, only the last attempt was considered. When the L7 retries were implemented, all retries were added before the server status adjutement. So only the last attempt was considered. To fix the issue, we must adjut the server status first, and then try to perform a L7 retry. This patch should fix the issue #2679. It must be backported to all stable versions. --- src/http_ana.c | 62 ++++++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/src/http_ana.c b/src/http_ana.c index 95b146ce3..0a5ba007a 100644 --- a/src/http_ana.c +++ b/src/http_ana.c @@ -1234,8 +1234,11 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit) htx = htxbuf(&rep->buf); /* Parsing errors are caught here */ - if (htx->flags & HTX_FL_PARSING_ERROR) + if (htx->flags & HTX_FL_PARSING_ERROR) { + if (objt_server(s->target)) + health_adjust(__objt_server(s->target), HANA_STATUS_HTTP_HDRRSP); goto return_bad_res; + } if (htx->flags & HTX_FL_PROCESSING_ERROR) goto return_int_err; @@ -1257,6 +1260,8 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit) if (s->scb->flags & SC_FL_ERROR) { struct connection *conn = sc_conn(s->scb); + if (!(s->flags & SF_SRV_REUSED) && objt_server(s->target)) + health_adjust(__objt_server(s->target), HANA_STATUS_HTTP_READ_ERROR); if ((txn->flags & TX_L7_RETRY) && (s->be->retry_type & PR_RE_DISCONNECTED) && @@ -1279,10 +1284,8 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit) goto abort_keep_alive; _HA_ATOMIC_INC(&s->be->be_counters.failed_resp); - if (objt_server(s->target)) { + if (objt_server(s->target)) _HA_ATOMIC_INC(&__objt_server(s->target)->counters.failed_resp); - health_adjust(__objt_server(s->target), HANA_STATUS_HTTP_READ_ERROR); - } /* if the server refused the early data, just send a 425 */ if (conn && conn->err_code == CO_ER_SSL_EARLY_FAILED) @@ -1306,6 +1309,9 @@ 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 (objt_server(s->target)) + health_adjust(__objt_server(s->target), HANA_STATUS_HTTP_READ_TIMEOUT); + if ((txn->flags & TX_L7_RETRY) && (s->be->retry_type & PR_RE_TIMEOUT)) { if (co_data(rep) || do_l7_retry(s, s->scb) == 0) { @@ -1315,10 +1321,8 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit) } } _HA_ATOMIC_INC(&s->be->be_counters.failed_resp); - if (objt_server(s->target)) { + if (objt_server(s->target)) _HA_ATOMIC_INC(&__objt_server(s->target)->counters.failed_resp); - health_adjust(__objt_server(s->target), HANA_STATUS_HTTP_READ_TIMEOUT); - } txn->status = 504; stream_inc_http_fail_ctr(s); @@ -1360,6 +1364,9 @@ 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 (s->scb->flags & (SC_FL_EOS|SC_FL_ABRT_DONE)) { + if (!(s->flags & SF_SRV_REUSED) && objt_server(s->target)) + health_adjust(__objt_server(s->target), HANA_STATUS_HTTP_BROKEN_PIPE); + if ((txn->flags & TX_L7_RETRY) && (s->be->retry_type & PR_RE_DISCONNECTED)) { if (co_data(rep) || do_l7_retry(s, s->scb) == 0) { @@ -1373,10 +1380,8 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit) goto abort_keep_alive; _HA_ATOMIC_INC(&s->be->be_counters.failed_resp); - if (objt_server(s->target)) { + if (objt_server(s->target)) _HA_ATOMIC_INC(&__objt_server(s->target)->counters.failed_resp); - health_adjust(__objt_server(s->target), HANA_STATUS_HTTP_BROKEN_PIPE); - } txn->status = 502; stream_inc_http_fail_ctr(s); @@ -1427,6 +1432,17 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit) BUG_ON(htx_get_first_type(htx) != HTX_BLK_RES_SL); sl = http_get_stline(htx); + /* Adjust server's health based on status code. Note: status codes 501 + * and 505 are triggered on demand by client request, so we must not + * count them as server failures. + */ + if (objt_server(s->target)) { + if (sl->info.res.status >= 100 && (sl->info.res.status < 500 || sl->info.res.status == 501 || sl->info.res.status == 505)) + health_adjust(__objt_server(s->target), HANA_STATUS_HTTP_OK); + else + health_adjust(__objt_server(s->target), HANA_STATUS_HTTP_STS); + } + /* Perform a L7 retry because of the status code */ if ((txn->flags & TX_L7_RETRY) && l7_status_match(s->be, sl->info.res.status) && @@ -1499,17 +1515,6 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit) _HA_ATOMIC_INC(&__objt_server(s->target)->counters.p.http.cum_req); } - /* Adjust server's health based on status code. Note: status codes 501 - * and 505 are triggered on demand by client request, so we must not - * count them as server failures. - */ - if (objt_server(s->target)) { - if (txn->status >= 100 && (txn->status < 500 || txn->status == 501 || txn->status == 505)) - health_adjust(__objt_server(s->target), HANA_STATUS_HTTP_OK); - else - health_adjust(__objt_server(s->target), HANA_STATUS_HTTP_STS); - } - /* * We may be facing a 100-continue response, or any other informational * 1xx response which is non-final, in which case this is not the right @@ -1535,8 +1540,11 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit) * header content. But it is probably stronger enough for now. */ if (txn->status == 101 && - (!(txn->req.flags & HTTP_MSGF_CONN_UPG) || !(txn->rsp.flags & HTTP_MSGF_CONN_UPG))) + (!(txn->req.flags & HTTP_MSGF_CONN_UPG) || !(txn->rsp.flags & HTTP_MSGF_CONN_UPG))) { + if (objt_server(s->target)) + health_adjust(__objt_server(s->target), HANA_STATUS_HTTP_HDRRSP); goto return_bad_res; + } /* * 2: check for cacheability. @@ -1657,11 +1665,6 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit) goto return_prx_cond; return_bad_res: - _HA_ATOMIC_INC(&s->be->be_counters.failed_resp); - if (objt_server(s->target)) { - _HA_ATOMIC_INC(&__objt_server(s->target)->counters.failed_resp); - health_adjust(__objt_server(s->target), HANA_STATUS_HTTP_HDRRSP); - } if ((s->be->retry_type & PR_RE_JUNK_REQUEST) && (txn->flags & TX_L7_RETRY) && do_l7_retry(s, s->scb) == 0) { @@ -1669,6 +1672,11 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit) STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA, s, txn); return 0; } + + _HA_ATOMIC_INC(&s->be->be_counters.failed_resp); + if (objt_server(s->target)) + _HA_ATOMIC_INC(&__objt_server(s->target)->counters.failed_resp); + txn->status = 502; stream_inc_http_fail_ctr(s); /* fall through */