]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: tcpcheck: Be able to expect an empty response
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 20 Mar 2023 15:49:51 +0000 (16:49 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 5 Apr 2023 06:46:06 +0000 (08:46 +0200)
It is not possible to successfully match an empty response. However using
regex, it should be possible to reject response with any content. For
instance:

   tcp-check expect !rstring ".+"

It may seem a be strange to do that, but it is possible, it is a valid
config. So it must work. Thanks to this patch, it is now really supported.

This patch may be backported as far as 2.2. But only if someone ask for it.

src/tcpcheck.c

index 288bd19d75b1966db699d671b3fa73886700315c..085f42768a17389da26f096395ad10efc93d86c4 100644 (file)
@@ -421,6 +421,7 @@ static void tcpcheck_expect_onerror_message(struct buffer *msg, struct check *ch
                                            int match, struct ist info)
 {
        struct sample *smp;
+       int is_empty;
 
        /* Follows these step to produce the info message:
         *     1. if info field is already provided, copy it
@@ -438,9 +439,18 @@ static void tcpcheck_expect_onerror_message(struct buffer *msg, struct check *ch
                goto comment;
        }
 
-       if (check->type == PR_O2_TCPCHK_CHK &&
-          (check->tcpcheck_rules->flags & TCPCHK_RULES_PROTO_CHK) != TCPCHK_RULES_TCP_CHK)
-              goto comment;
+       is_empty = (IS_HTX_SC(check->sc) ? htx_is_empty(htxbuf(&check->bi)) : !b_data(&check->bi));
+       if (is_empty) {
+               TRACE_ERROR("empty response", CHK_EV_RX_DATA|CHK_EV_RX_ERR, check);
+               chunk_printf(msg, "TCPCHK got an empty response at step %d",
+                            tcpcheck_get_step_id(check, rule));
+               goto comment;
+       }
+
+       if (check->type == PR_O2_TCPCHK_CHK &&
+           (check->tcpcheck_rules->flags & TCPCHK_RULES_PROTO_CHK) != TCPCHK_RULES_TCP_CHK) {
+               goto comment;
+       }
 
        chunk_strcat(msg, (match ? "TCPCHK matched unwanted content" : "TCPCHK did not match content"));
        switch (rule->expect.type) {
@@ -1597,31 +1607,10 @@ enum tcpcheck_eval_ret tcpcheck_eval_recv(struct check *check, struct tcpcheck_r
                TRACE_ERROR("connection error during recv", CHK_EV_RX_DATA|CHK_EV_RX_ERR, check);
                goto stop;
        }
-       if (!cur_read) {
-               if (sc_ep_test(sc, SE_FL_EOI)) {
-                       /* If EOI is set, it means there is a response or an error */
-                       goto out;
-               }
-
-               if (!sc_ep_test(sc, SE_FL_WANT_ROOM | SE_FL_ERROR | SE_FL_EOS)) {
-                       conn->mux->subscribe(sc, SUB_RETRY_RECV, &sc->wait_event);
-                       TRACE_DEVEL("waiting for response", CHK_EV_RX_DATA, check);
-                       goto wait_more_data;
-               }
-
-               if (is_empty) {
-                       int status;
-
-                       chunk_printf(&trash, "TCPCHK got an empty response at step %d",
-                                    tcpcheck_get_step_id(check, rule));
-                       if (rule->comment)
-                               chunk_appendf(&trash, " comment: '%s'", rule->comment);
-
-                       TRACE_ERROR("empty response", CHK_EV_RX_DATA|CHK_EV_RX_ERR, check);
-                       status = ((rule->expect.err_status != HCHK_STATUS_UNKNOWN) ? rule->expect.err_status : HCHK_STATUS_L7RSP);
-                       set_server_check_status(check, status, trash.area);
-                       goto stop;
-               }
+       else if (!cur_read && !sc_ep_test(sc, SE_FL_WANT_ROOM | SE_FL_ERROR | SE_FL_EOS)) {
+               conn->mux->subscribe(sc, SUB_RETRY_RECV, &sc->wait_event);
+               TRACE_DEVEL("waiting for response", CHK_EV_RX_DATA, check);
+               goto wait_more_data;
        }
        TRACE_DATA("data received", CHK_EV_RX_DATA, check, 0, 0, (size_t[]){cur_read});