REORG: cli: move the "set rate-limit" functions to their own parser

All 4 rate-limit settings were handled at once given that exactly the
same checks are performed on them. In case of missing or incorrect
argument, the detailed supported options are printed with their use
case.

This was the last specific entry in the CLI parser, some additional
cleanup may still be done.
diff --git a/src/cli.c b/src/cli.c
index 060ee23..95ebd70 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -73,7 +73,6 @@
 	"  help           : this message\n"
 	"  prompt         : toggle interactive mode with prompt\n"
 	"  quit           : disconnect\n"
-	"  set rate-limit : change a rate limiting value\n"
 	"";
 
 static const char stats_permission_denied_msg[] =
@@ -400,7 +399,6 @@
  */
 static int stats_sock_parse_request(struct stream_interface *si, char *line)
 {
-	struct stream *s = si_strm(si);
 	struct appctx *appctx = __objt_appctx(si->end);
 	char *args[MAX_STATS_ARGS + 1];
 	struct cli_kw *kw;
@@ -459,161 +457,10 @@
 				appctx->io_handler = kw->io_handler;
 				appctx->io_release = kw->io_release;
 			}
-		}
-	}
-	else if (strcmp(args[0], "set") == 0) {
-		if (strcmp(args[1], "rate-limit") == 0) {
-			if (strcmp(args[2], "connections") == 0) {
-				if (strcmp(args[3], "global") == 0) {
-					int v;
-
-					if (strm_li(s)->bind_conf->level < ACCESS_LVL_ADMIN) {
-						appctx->ctx.cli.msg = stats_permission_denied_msg;
-						appctx->st0 = STAT_CLI_PRINT;
-						return 1;
-					}
-
-					if (!*args[4]) {
-						appctx->ctx.cli.msg = "Expects an integer value.\n";
-						appctx->st0 = STAT_CLI_PRINT;
-						return 1;
-					}
-
-					v = atoi(args[4]);
-					if (v < 0) {
-						appctx->ctx.cli.msg = "Value out of range.\n";
-						appctx->st0 = STAT_CLI_PRINT;
-						return 1;
-					}
-
-					global.cps_lim = v;
-
-					/* Dequeues all of the listeners waiting for a resource */
-					if (!LIST_ISEMPTY(&global_listener_queue))
-						dequeue_all_listeners(&global_listener_queue);
-
-					return 1;
-				}
-				else {
-					appctx->ctx.cli.msg = "'set rate-limit connections' only supports 'global'.\n";
-					appctx->st0 = STAT_CLI_PRINT;
-					return 1;
-				}
-			}
-			else if (strcmp(args[2], "sessions") == 0) {
-				if (strcmp(args[3], "global") == 0) {
-					int v;
-
-					if (strm_li(s)->bind_conf->level < ACCESS_LVL_ADMIN) {
-						appctx->ctx.cli.msg = stats_permission_denied_msg;
-						appctx->st0 = STAT_CLI_PRINT;
-						return 1;
-					}
-
-					if (!*args[4]) {
-						appctx->ctx.cli.msg = "Expects an integer value.\n";
-						appctx->st0 = STAT_CLI_PRINT;
-						return 1;
-					}
-
-					v = atoi(args[4]);
-					if (v < 0) {
-						appctx->ctx.cli.msg = "Value out of range.\n";
-						appctx->st0 = STAT_CLI_PRINT;
-						return 1;
-					}
-
-					global.sps_lim = v;
-
-					/* Dequeues all of the listeners waiting for a resource */
-					if (!LIST_ISEMPTY(&global_listener_queue))
-						dequeue_all_listeners(&global_listener_queue);
-
-					return 1;
-				}
-				else {
-					appctx->ctx.cli.msg = "'set rate-limit sessions' only supports 'global'.\n";
-					appctx->st0 = STAT_CLI_PRINT;
-					return 1;
-				}
-			}
-#ifdef USE_OPENSSL
-			else if (strcmp(args[2], "ssl-sessions") == 0) {
-				if (strcmp(args[3], "global") == 0) {
-					int v;
-
-					if (strm_li(s)->bind_conf->level < ACCESS_LVL_ADMIN) {
-						appctx->ctx.cli.msg = stats_permission_denied_msg;
-						appctx->st0 = STAT_CLI_PRINT;
-						return 1;
-					}
-
-					if (!*args[4]) {
-						appctx->ctx.cli.msg = "Expects an integer value.\n";
-						appctx->st0 = STAT_CLI_PRINT;
-						return 1;
-					}
-
-					v = atoi(args[4]);
-					if (v < 0) {
-						appctx->ctx.cli.msg = "Value out of range.\n";
-						appctx->st0 = STAT_CLI_PRINT;
-						return 1;
-					}
-
-					global.ssl_lim = v;
-
-					/* Dequeues all of the listeners waiting for a resource */
-					if (!LIST_ISEMPTY(&global_listener_queue))
-						dequeue_all_listeners(&global_listener_queue);
-
-					return 1;
-				}
-				else {
-					appctx->ctx.cli.msg = "'set rate-limit ssl-sessions' only supports 'global'.\n";
-					appctx->st0 = STAT_CLI_PRINT;
-					return 1;
-				}
-			}
-#endif
-			else if (strcmp(args[2], "http-compression") == 0) {
-				if (strcmp(args[3], "global") == 0) {
-					int v;
-
-					if (strm_li(s)->bind_conf->level < ACCESS_LVL_ADMIN) {
-						appctx->ctx.cli.msg = stats_permission_denied_msg;
-						appctx->st0 = STAT_CLI_PRINT;
-						return 1;
-					}
-
-					if (!*args[4]) {
-						appctx->ctx.cli.msg = "Expects a maximum input byte rate in kB/s.\n";
-						appctx->st0 = STAT_CLI_PRINT;
-						return 1;
-					}
-
-					v = atoi(args[4]);
-					global.comp_rate_lim = v * 1024; /* Kilo to bytes. */
-				}
-				else {
-					appctx->ctx.cli.msg = "'set rate-limit http-compression' only supports 'global'.\n";
-					appctx->st0 = STAT_CLI_PRINT;
-					return 1;
-				}
-			}
-			else {
-				appctx->ctx.cli.msg = "'set rate-limit' supports 'connections', 'sessions', 'ssl-sessions', and 'http-compression'.\n";
-				appctx->st0 = STAT_CLI_PRINT;
-				return 1;
-			}
-		} else { /* unknown "set" parameter */
-			return 0;
 		}
-	}
-	else { /* not "show" nor "clear" nor "get" nor "set" nor "enable" nor "disable" */
-		return 0;
+		return 1;
 	}
-	return 1;
+	return 0;
 }
 
 /* This I/O handler runs as an applet embedded in a stream interface. It is
@@ -968,6 +815,63 @@
 	return 1;
 }
 
+/* parse a "set rate-limit" command. It always returns 1. */
+static int cli_parse_set_ratelimit(char **args, struct appctx *appctx, void *private)
+{
+	int v;
+	int *res;
+	int mul = 1;
+
+	if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
+		return 1;
+
+	if (strcmp(args[2], "connections") == 0 && strcmp(args[3], "global") == 0)
+		res = &global.cps_lim;
+	else if (strcmp(args[2], "sessions") == 0 && strcmp(args[3], "global") == 0)
+		res = &global.sps_lim;
+#ifdef USE_OPENSSL
+	else if (strcmp(args[2], "ssl-sessions") == 0 && strcmp(args[3], "global") == 0)
+		res = &global.ssl_lim;
+#endif
+	else if (strcmp(args[2], "http-compression") == 0 && strcmp(args[3], "global") == 0) {
+		res = &global.comp_rate_lim;
+		mul = 1024;
+	}
+	else {
+		appctx->ctx.cli.msg =
+			"'set rate-limit' only supports :\n"
+			"   - 'connections global' to set the per-process maximum connection rate\n"
+			"   - 'sessions global' to set the per-process maximum session rate\n"
+#ifdef USE_OPENSSL
+			"   - 'ssl-session global' to set the per-process maximum SSL session rate\n"
+#endif
+			"   - 'http-compression global' to set the per-process maximum compression speed in kB/s\n";
+		appctx->st0 = STAT_CLI_PRINT;
+		return 1;
+	}
+
+	if (!*args[4]) {
+		appctx->ctx.cli.msg = "Expects an integer value.\n";
+		appctx->st0 = STAT_CLI_PRINT;
+		return 1;
+	}
+
+	v = atoi(args[4]);
+	if (v < 0) {
+		appctx->ctx.cli.msg = "Value out of range.\n";
+		appctx->st0 = STAT_CLI_PRINT;
+		return 1;
+	}
+
+	*res = v * mul;
+
+	/* Dequeues all of the listeners waiting for a resource */
+	if (!LIST_ISEMPTY(&global_listener_queue))
+		dequeue_all_listeners(&global_listener_queue);
+
+	return 1;
+}
+
 /* parse the "level" argument on the bind lines */
 static int bind_parse_level(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
 {
@@ -1001,6 +905,7 @@
 /* register cli keywords */
 static struct cli_kw_list cli_kws = {{ },{
 	{ { "set", "maxconn", "global",  NULL }, "set maxconn global : change the per-process maxconn setting", cli_parse_set_maxconn_global, NULL },
+	{ { "set", "rate-limit", NULL }, "set rate-limit : change a rate limiting value", cli_parse_set_ratelimit, NULL },
 	{ { "set", "timeout",  NULL }, "set timeout    : change a timeout setting", cli_parse_set_timeout, NULL, NULL },
 	{ { "show", "env",  NULL }, "show env [var] : dump environment variables known to the process", cli_parse_show_env, cli_io_handler_show_env, NULL },
 	{{},}