DEBUG: stream: Add debug counters to track some client/server aborts
authorChristopher Faulet <cfaulet@haproxy.com>
Tue, 22 Oct 2024 14:46:34 +0000 (16:46 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 22 Apr 2025 09:05:28 +0000 (11:05 +0200)
Not all aborts are tracked for now but only those a bit ambiguous. Mainly,
aborts during the data forwarding are concerned. Those triggered during the
request or the response analysis are easier to analyze with the stream
termination state.

(cherry picked from commit c8aecc393bd125e476469d2b6159a1af542c78ae)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>

src/http_ana.c
src/stream.c

index d7300c7..3de1cf1 100644 (file)
@@ -501,8 +501,9 @@ int http_process_req_common(struct stream *s, struct channel *req, int an_bit, s
                        if (!ret)
                                continue;
                }
-               if (!http_apply_redirect_rule(rule, s, txn))
+               if (!http_apply_redirect_rule(rule, s, txn)) {
                        goto return_int_err;
+               }
                goto done;
        }
 
@@ -994,8 +995,10 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
                 * responsability to handle the error. It is especially
                 * important to properly handle L7-retries but also K/A silent close.
                 */
-               if (txn->rsp.msg_state >= HTTP_MSG_BODY && htx_is_empty(htxbuf(&s->res.buf)))
+               if (txn->rsp.msg_state >= HTTP_MSG_BODY && htx_is_empty(htxbuf(&s->res.buf))) {
+                       COUNT_IF(1, "Server abort during request forwarding");
                        goto return_srv_abort;
+               }
        }
 
        http_end_request(s);
@@ -1027,8 +1030,10 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
 
  missing_data_or_waiting:
        /* stop waiting for data if the input is closed before the end */
-       if (msg->msg_state < HTTP_MSG_ENDING && (s->scf->flags & (SC_FL_ABRT_DONE|SC_FL_EOS)))
+       if (msg->msg_state < HTTP_MSG_ENDING && (s->scf->flags & (SC_FL_ABRT_DONE|SC_FL_EOS))) {
+               COUNT_IF(1, "Client abort during request forwarding");
                goto return_cli_abort;
+       }
 
  waiting:
        /* waiting for the last bits to leave the buffer */
@@ -1038,8 +1043,10 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
                 * to handle the error. It is especially important to properly
                 * handle L7-retries but also K/A silent close.
                 */
-               if (txn->rsp.msg_state >= HTTP_MSG_BODY && htx_is_empty(htxbuf(&s->res.buf)))
+               if (txn->rsp.msg_state >= HTTP_MSG_BODY && htx_is_empty(htxbuf(&s->res.buf))) {
+                       COUNT_IF(1, "Server abort during request forwarding");
                        goto return_srv_abort;
+               }
        }
 
        /* When TE: chunked is used, we need to get there again to parse remaining
@@ -1102,6 +1109,7 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
        if (objt_server(s->target))
                _HA_ATOMIC_INC(&__objt_server(s->target)->counters.internal_errors);
        status = 500;
+       COUNT_IF(1, "Internal error during request forwarding");
        goto return_prx_cond;
 
   return_bad_req:
@@ -1109,6 +1117,7 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
        if (sess->listener && sess->listener->counters)
                _HA_ATOMIC_INC(&sess->listener->counters->failed_req);
        status = 400;
+       COUNT_IF(1, "Request parsing error during request forwarding");
        /* fall through */
 
   return_prx_cond:
@@ -2140,6 +2149,7 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
        if ((s->scf->flags & SC_FL_SHUT_DONE) && co_data(res)) {
                /* response errors are most likely due to the client aborting
                 * the transfer. */
+               COUNT_IF(1, "Client abort during response forwarding");
                goto return_cli_abort;
        }
 
@@ -2153,8 +2163,10 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
        return 0;
 
   missing_data_or_waiting:
-       if (s->scf->flags & SC_FL_SHUT_DONE)
+       if (s->scf->flags & SC_FL_SHUT_DONE) {
+               COUNT_IF(1, "Client abort during response forwarding");
                goto return_cli_abort;
+       }
 
        /* stop waiting for data if the input is closed before the end. If the
         * client side was already closed, it means that the client has aborted,
@@ -2162,11 +2174,15 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
         * server abort.
         */
        if (msg->msg_state < HTTP_MSG_ENDING && (s->scb->flags & (SC_FL_EOS|SC_FL_ABRT_DONE))) {
-               if ((s->scb->flags & (SC_FL_ABRT_DONE|SC_FL_SHUT_DONE)) == (SC_FL_ABRT_DONE|SC_FL_SHUT_DONE))
+               if ((s->scb->flags & (SC_FL_ABRT_DONE|SC_FL_SHUT_DONE)) == (SC_FL_ABRT_DONE|SC_FL_SHUT_DONE)) {
+                       COUNT_IF(1, "Client abort during response forwarding");
                        goto return_cli_abort;
+               }
                /* If we have some pending data, we continue the processing */
-               if (htx_is_empty(htx))
+               if (htx_is_empty(htx)) {
+                       COUNT_IF(1, "Server abort during response forwarding");
                        goto return_srv_abort;
+               }
        }
 
        /* When TE: chunked is used, we need to get there again to parse
@@ -2226,6 +2242,7 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
                _HA_ATOMIC_INC(&__objt_server(s->target)->counters.internal_errors);
        if (!(s->flags & SF_ERR_MASK))
                s->flags |= SF_ERR_INTERNAL;
+       COUNT_IF(1, "Internal error during response forwarding");
        goto return_error;
 
   return_bad_res:
@@ -2235,6 +2252,7 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
                health_adjust(__objt_server(s->target), HANA_STATUS_HTTP_RSP);
        }
        stream_inc_http_fail_ctr(s);
+       COUNT_IF(1, "Response parsing error during response forwarding");
        /* fall through */
 
    return_error:
index f17df07..5cee7d7 100644 (file)
@@ -1839,6 +1839,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state)
                        sc_shutdown(scf);
                        //sc_report_error(scf); TODO: Be sure it is useless
                        if (!(req->analysers) && !(res->analysers)) {
+                               COUNT_IF(1, "Report a client abort (no analysers)");
                                _HA_ATOMIC_INC(&s->be->be_counters.cli_aborts);
                                _HA_ATOMIC_INC(&sess->fe->fe_counters.cli_aborts);
                                if (sess->listener && sess->listener->counters)
@@ -1862,6 +1863,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state)
                        if (srv)
                                _HA_ATOMIC_INC(&srv->counters.failed_resp);
                        if (!(req->analysers) && !(res->analysers)) {
+                               COUNT_IF(1, "Report a client abort (no analysers)");
                                _HA_ATOMIC_INC(&s->be->be_counters.srv_aborts);
                                _HA_ATOMIC_INC(&sess->fe->fe_counters.srv_aborts);
                                if (sess->listener && sess->listener->counters)
@@ -2167,6 +2169,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state)
                                if (srv)
                                        _HA_ATOMIC_INC(&srv->counters.cli_aborts);
                                s->flags |= SF_ERR_CLICL;
+                               COUNT_IF(1, "Report unhandled client error");
                        }
                        else if (req->flags & CF_READ_TIMEOUT) {
                                _HA_ATOMIC_INC(&s->be->be_counters.cli_aborts);
@@ -2176,6 +2179,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state)
                                if (srv)
                                        _HA_ATOMIC_INC(&srv->counters.cli_aborts);
                                s->flags |= SF_ERR_CLITO;
+                               COUNT_IF(1, "Report unhandled client timeout (RD)");
                        }
                        else {
                                _HA_ATOMIC_INC(&s->be->be_counters.srv_aborts);
@@ -2185,6 +2189,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state)
                                if (srv)
                                        _HA_ATOMIC_INC(&srv->counters.srv_aborts);
                                s->flags |= SF_ERR_SRVTO;
+                               COUNT_IF(1, "Report unhandled server timeout (WR)");
                        }
                        sess_set_term_flags(s);
 
@@ -2213,6 +2218,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state)
                                if (srv)
                                        _HA_ATOMIC_INC(&srv->counters.srv_aborts);
                                s->flags |= SF_ERR_SRVCL;
+                               COUNT_IF(1, "Report unhandled server error");
                        }
                        else if (res->flags & CF_READ_TIMEOUT) {
                                _HA_ATOMIC_INC(&s->be->be_counters.srv_aborts);
@@ -2222,6 +2228,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state)
                                if (srv)
                                        _HA_ATOMIC_INC(&srv->counters.srv_aborts);
                                s->flags |= SF_ERR_SRVTO;
+                               COUNT_IF(1, "Report unhandled server timeout (RD)");
                        }
                        else {
                                _HA_ATOMIC_INC(&s->be->be_counters.cli_aborts);
@@ -2231,6 +2238,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state)
                                if (srv)
                                        _HA_ATOMIC_INC(&srv->counters.cli_aborts);
                                s->flags |= SF_ERR_CLITO;
+                               COUNT_IF(1, "Report unhandled client timeout (WR)");
                        }
                        sess_set_term_flags(s);
                }