]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MAJOR: cli: Update the CLI applet to handle its own buffers
authorChristopher Faulet <cfaulet@haproxy.com>
Thu, 15 Feb 2024 12:34:05 +0000 (13:34 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Thu, 28 Mar 2024 16:32:51 +0000 (17:32 +0100)
It is the third applet to be refactored to use its own buffers. In addition to
the CLI applet, some I/O handlers of CLI commands were also updated, especially
the stats ones.

Some command I/O handlers were updated to use applet's buffers instead of
channels ones.

src/cli.c
src/http_client.c
src/proxy.c
src/stats.c

index 389f19efab57ce7806230e95b4eda4d480e4953d..bbc1df4d94cd49fd6288fb14fb0d67ec986e6253 100644 (file)
--- a/src/cli.c
+++ b/src/cli.c
@@ -910,34 +910,36 @@ static int cli_output_msg(struct appctx *appctx, const char *msg, int severity,
  */
 static void cli_io_handler(struct appctx *appctx)
 {
-       struct stconn *sc = appctx_sc(appctx);
-       struct channel *res = sc_ic(sc);
-       struct bind_conf *bind_conf = strm_li(__sc_strm(sc))->bind_conf;
        int reql;
        int len;
        int lf = 0;
 
-       if (unlikely(se_fl_test(appctx->sedesc, (SE_FL_EOS|SE_FL_ERROR)))) {
-               co_skip(sc_oc(sc), co_data(sc_oc(sc)));
+       if (applet_fl_test(appctx, APPCTX_FL_OUTBLK_ALLOC|APPCTX_FL_OUTBLK_FULL))
+               goto out;
+
+       if (!appctx_get_buf(appctx, &appctx->outbuf)) {
+               applet_fl_set(appctx, APPCTX_FL_OUTBLK_ALLOC);
                goto out;
        }
 
-       /* Check if the input buffer is available. */
-       if (!b_size(&res->buf)) {
-               sc_need_room(sc, 0);
+       if (unlikely(applet_fl_test(appctx, APPCTX_FL_EOS|APPCTX_FL_ERROR))) {
+               appctx->st0 = CLI_ST_END;
                goto out;
        }
 
        while (1) {
                if (appctx->st0 == CLI_ST_INIT) {
                        /* reset severity to default at init */
+                       struct stconn *sc = appctx_sc(appctx);
+                       struct bind_conf *bind_conf = strm_li(__sc_strm(sc))->bind_conf;
+
                        appctx->cli_severity_output = bind_conf->severity_output;
                        applet_reset_svcctx(appctx);
                        appctx->st0 = CLI_ST_GETREQ;
                        appctx->cli_level = bind_conf->level;
                }
                else if (appctx->st0 == CLI_ST_END) {
-                       se_fl_set(appctx->sedesc, SE_FL_EOS);
+                       applet_set_eos(appctx);
                        free_trash_chunk(appctx->chunk);
                        appctx->chunk = NULL;
                        break;
@@ -960,8 +962,8 @@ static void cli_io_handler(struct appctx *appctx)
                        /* ensure we have some output room left in the event we
                         * would want to return some info right after parsing.
                         */
-                       if (buffer_almost_full(sc_ib(sc))) {
-                               sc_need_room(sc, b_size(&res->buf) / 2);
+                       if (buffer_almost_full(&appctx->outbuf)) {
+                               applet_fl_set(appctx, APPCTX_FL_OUTBLK_FULL);
                                break;
                        }
 
@@ -972,19 +974,30 @@ static void cli_io_handler(struct appctx *appctx)
                         */
 
                        if (appctx->st1 & APPCTX_CLI_ST1_PAYLOAD)
-                               reql = co_getline(sc_oc(sc), str,
-                                                 appctx->chunk->size - appctx->chunk->data - 1);
+                               reql = b_getline(&appctx->inbuf, 0, b_data(&appctx->inbuf), str,
+                                                appctx->chunk->size - appctx->chunk->data - 1);
                        else
-                               reql = co_getdelim(sc_oc(sc), str,
-                                                  appctx->chunk->size - appctx->chunk->data - 1,
-                                                  "\n;", '\\');
-
-                       if (reql <= 0) { /* closed or EOL not found */
-                               if (reql == 0)
-                                       break;
-                               se_fl_set(appctx->sedesc, SE_FL_ERROR);
-                               appctx->st0 = CLI_ST_END;
-                               continue;
+                               reql = b_getdelim(&appctx->inbuf, 0, b_data(&appctx->inbuf), str,
+                                                 appctx->chunk->size - appctx->chunk->data - 1,
+                                                 "\n;", '\\');
+
+                       if (!reql) {
+                               /* Line not found. Report an error if the input buffer is full, if there is not
+                                * enough space in the chunk or if a shutdown occurred.
+                                * Otherwise, wait for more data */
+                               if (applet_fl_test(appctx, APPCTX_FL_INBLK_FULL) ||
+                                   b_data(&appctx->inbuf) > appctx->chunk->size - appctx->chunk->data - 1) {
+                                       applet_set_eos(appctx);
+                                       applet_set_error(appctx);
+                                       cli_err(appctx, "The command is too big for the buffer size. Please change tune.bufsize in the configuration to use a bigger command.\n");
+                                       goto cli_output;
+                               }
+                               if (se_fl_test(appctx->sedesc, SE_FL_SHW)) {
+                                       applet_set_error(appctx);
+                                       appctx->st0 = CLI_ST_END;
+                                       continue;
+                               }
+                               break;
                        }
 
                        if (str[reql-1] == '\n')
@@ -996,12 +1009,8 @@ static void cli_io_handler(struct appctx *appctx)
                         */
                        len = reql - 1;
                        if (str[len] != '\n' && str[len] != ';') {
-                               se_fl_set(appctx->sedesc, SE_FL_ERROR);
-                               if (reql == appctx->chunk->size - appctx->chunk->data - 1) {
-                                       cli_err(appctx, "The command is too big for the buffer size. Please change tune.bufsize in the configuration to use a bigger command.\n");
-                                       co_skip(sc_oc(sc), co_data(sc_oc(sc)));
-                                       goto cli_output;
-                               }
+                               applet_set_eos(appctx);
+                               applet_set_error(appctx);
                                appctx->st0 = CLI_ST_END;
                                continue;
                        }
@@ -1082,8 +1091,7 @@ static void cli_io_handler(struct appctx *appctx)
                        }
 
                        /* re-adjust req buffer */
-                       co_skip(sc_oc(sc), reql);
-                       sc_opposite(sc)->flags |= SC_FL_RCV_ONCE; /* we plan to read small requests */
+                       b_del(&appctx->inbuf, reql);
                }
                else {  /* output functions */
                        struct cli_print_ctx *ctx;
@@ -1205,10 +1213,10 @@ static void cli_io_handler(struct appctx *appctx)
                         * non-interactive mode.
                         */
                        if ((appctx->st1 & (APPCTX_CLI_ST1_PROMPT|APPCTX_CLI_ST1_PAYLOAD|APPCTX_CLI_ST1_LASTCMD)) == APPCTX_CLI_ST1_LASTCMD) {
-                               se_fl_set(appctx->sedesc, SE_FL_EOI);
-                               appctx->st0 = CLI_ST_END;
-                               continue;
-                       }
+                               applet_set_eoi(appctx);
+                               appctx->st0 = CLI_ST_END;
+                               continue;
+                       }
 
                        /* switch state back to GETREQ to read next requests */
                        applet_reset_svcctx(appctx);
@@ -1225,7 +1233,7 @@ static void cli_io_handler(struct appctx *appctx)
                         * refills the buffer with new bytes in non-interactive
                         * mode, avoiding to close on apparently empty commands.
                         */
-                       if (co_data(sc_oc(sc))) {
+                       if (b_data(&appctx->inbuf)) {
                                appctx_wakeup(appctx);
                                goto out;
                        }
@@ -1233,6 +1241,11 @@ static void cli_io_handler(struct appctx *appctx)
        }
 
  out:
+       if (appctx->st0 == CLI_ST_END) {
+               /* eat the whole request */
+               b_reset(&appctx->inbuf);
+               applet_fl_clr(appctx, APPCTX_FL_INBLK_FULL);
+       }
        return;
 }
 
@@ -2131,7 +2144,7 @@ static int cli_io_handler_wait(struct appctx *appctx)
 
  wait:
        /* Stop waiting upon close/abort/error */
-       if (unlikely(se_fl_test(appctx->sedesc, SE_FL_SHW))) {
+       if (unlikely(se_fl_test(appctx->sedesc, SE_FL_SHW)) && !b_data(&appctx->inbuf)) {
                ctx->error = CLI_WAIT_ERR_INTR;
                return 1;
        }
@@ -2139,6 +2152,7 @@ static int cli_io_handler_wait(struct appctx *appctx)
        return 0;
 }
 
+
 /* release structs allocated by "delete server" */
 static void cli_release_wait(struct appctx *appctx)
 {
@@ -3523,6 +3537,8 @@ static struct applet cli_applet = {
        .obj_type = OBJ_TYPE_APPLET,
        .name = "<CLI>", /* used for logging */
        .fct = cli_io_handler,
+       .rcv_buf = appctx_raw_rcv_buf,
+       .snd_buf = appctx_raw_snd_buf,
        .release = cli_release_handler,
 };
 
@@ -3531,6 +3547,8 @@ static struct applet mcli_applet = {
        .obj_type = OBJ_TYPE_APPLET,
        .name = "<MCLI>", /* used for logging */
        .fct = cli_io_handler,
+       .rcv_buf = appctx_raw_rcv_buf,
+       .snd_buf = appctx_raw_snd_buf,
        .release = cli_release_handler,
 };
 
index 4d3415cf0cece2adb1a2a8e43137332985c87302..e329954446f14402a4f4ff681f48d9b116d496e8 100644 (file)
@@ -190,7 +190,6 @@ err:
 static int hc_cli_io_handler(struct appctx *appctx)
 {
        struct hcli_svc_ctx *ctx = appctx->svcctx;
-       struct stconn *sc = appctx_sc(appctx);
        struct httpclient *hc = ctx->hc;
        struct http_hdr *hdrs, *hdr;
 
@@ -217,10 +216,7 @@ static int hc_cli_io_handler(struct appctx *appctx)
        }
 
        if (ctx->flags & HC_F_RES_BODY) {
-               int ret;
-
-               ret = httpclient_res_xfer(hc, sc_ib(sc));
-               channel_add_input(sc_ic(sc), ret); /* forward what we put in the buffer channel */
+               httpclient_res_xfer(hc, &appctx->outbuf);
 
                /* remove the flag if the buffer was emptied */
                if (httpclient_data(hc))
index 9adc6a2568071818e6ef592773f3644de46770ff..f87c3af2efd458f510776e4b4b0448350db3cd92 100644 (file)
@@ -3177,7 +3177,6 @@ static int cli_parse_show_errors(char **args, char *payload, struct appctx *appc
 static int cli_io_handler_show_errors(struct appctx *appctx)
 {
        struct show_errors_ctx *ctx = appctx->svcctx;
-       struct stconn *sc = appctx_sc(appctx);
        extern const char *monthname[12];
 
        chunk_reset(&trash);
@@ -3309,7 +3308,7 @@ static int cli_io_handler_show_errors(struct appctx *appctx)
                        newline = ctx->bol;
                        newptr = dump_text_line(&trash, es->buf, global.tune.bufsize, es->buf_len, &newline, ctx->ptr);
                        if (newptr == ctx->ptr) {
-                               sc_need_room(sc, 0);
+                               applet_fl_set(appctx, APPCTX_FL_OUTBLK_FULL);
                                goto cant_send_unlock;
                        }
 
index 39e232591dd270e55f4ec953fd9d9728124e3668..76fe2b70d5c64ff6b816573561c7a341ea07e36d 100644 (file)
@@ -346,10 +346,8 @@ int stats_is_full(struct appctx *appctx, struct buffer *buf, struct htx *htx)
                }
        }
        else {
-               struct channel *rep = sc_ic(appctx_sc(appctx));
-
-               if (buffer_almost_full(&rep->buf)) {
-                       sc_need_room(appctx_sc(appctx), b_size(&rep->buf) / 2);
+               if (buffer_almost_full(&appctx->outbuf))  {
+                       applet_fl_set(appctx, APPCTX_FL_OUTBLK_FULL);
                        goto full;
                }
        }