mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-21 13:51:26 +02:00
MEDIUM: cli: allow custom pattern for payload
The CLI payload syntax has some limitation, it can't handle payloads with empty lines, which is a common problem when uploading a PEM file over the CLI. This patch implements a way to customize the ending pattern of the CLI, so we can't look for other things than empty lines. A char cli_payload_pat[8] is used in the appctx to store the customized pattern. The pattern can't be more than 7 characters and can still empty to match an empty line. The cli_io_handler() identifies the pattern and stores it, and cli_parse_request() identifies the end of the payload. If the customized pattern between "<<" and "\n" is more than 7 characters, it is not considered as a pattern. This patch only implements the parser for the 'stats socket', another patch is needed for the 'master CLI'.
This commit is contained in:
parent
23c810d042
commit
e3557c7d45
@ -70,6 +70,7 @@ struct appctx {
|
|||||||
if the command is terminated or the session released */
|
if the command is terminated or the session released */
|
||||||
int cli_severity_output; /* used within the cli_io_handler to format severity output of informational feedback */
|
int cli_severity_output; /* used within the cli_io_handler to format severity output of informational feedback */
|
||||||
int cli_level; /* the level of CLI which can be lowered dynamically */
|
int cli_level; /* the level of CLI which can be lowered dynamically */
|
||||||
|
char cli_payload_pat[8]; /* Payload pattern */
|
||||||
uint32_t cli_anon_key; /* the key to anonymise with the hash in cli */
|
uint32_t cli_anon_key; /* the key to anonymise with the hash in cli */
|
||||||
struct buffer_wait buffer_wait; /* position in the list of objects waiting for a buffer */
|
struct buffer_wait buffer_wait; /* position in the list of objects waiting for a buffer */
|
||||||
struct task *t; /* task associated to the applet */
|
struct task *t; /* task associated to the applet */
|
||||||
|
75
src/cli.c
75
src/cli.c
@ -757,13 +757,22 @@ static int cli_parse_request(struct appctx *appctx)
|
|||||||
if (!*p)
|
if (!*p)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (strcmp(p, PAYLOAD_PATTERN) == 0) {
|
/* first check if the '<<' is present, but this is not enough
|
||||||
/* payload pattern recognized here, this is not an arg anymore,
|
* because we don't know if this is the end of the string */
|
||||||
* the payload starts at the first byte that follows the zero
|
if (strncmp(p, PAYLOAD_PATTERN, strlen(PAYLOAD_PATTERN)) == 0) {
|
||||||
* after the pattern.
|
int pat_len = strlen(appctx->cli_payload_pat);
|
||||||
*/
|
|
||||||
payload = p + strlen(PAYLOAD_PATTERN) + 1;
|
/* then if the customized pattern is empty, check if the next character is '\0' */
|
||||||
break;
|
if (pat_len == 0 && p[strlen(PAYLOAD_PATTERN)] == '\0') {
|
||||||
|
payload = p + strlen(PAYLOAD_PATTERN) + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* else if we found the customized pattern at the end of the string */
|
||||||
|
if (strcmp(p + strlen(PAYLOAD_PATTERN), appctx->cli_payload_pat) == 0) {
|
||||||
|
payload = p + strlen(PAYLOAD_PATTERN) + pat_len + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
args[i] = p;
|
args[i] = p;
|
||||||
@ -1010,29 +1019,53 @@ static void cli_io_handler(struct appctx *appctx)
|
|||||||
appctx->st0 = CLI_ST_PROMPT;
|
appctx->st0 = CLI_ST_PROMPT;
|
||||||
|
|
||||||
if (appctx->st1 & APPCTX_CLI_ST1_PAYLOAD) {
|
if (appctx->st1 & APPCTX_CLI_ST1_PAYLOAD) {
|
||||||
/* empty line */
|
/* look for a pattern */
|
||||||
if (!len) {
|
if (len == strlen(appctx->cli_payload_pat)) {
|
||||||
/* remove the last two \n */
|
/* here use 'len' because str still contains the \n */
|
||||||
appctx->chunk->data -= 2;
|
if (strncmp(str, appctx->cli_payload_pat, len) == 0) {
|
||||||
appctx->chunk->area[appctx->chunk->data] = 0;
|
/* remove the last two \n */
|
||||||
cli_parse_request(appctx);
|
appctx->chunk->data -= strlen(appctx->cli_payload_pat) + 2;
|
||||||
chunk_reset(appctx->chunk);
|
appctx->chunk->area[appctx->chunk->data] = 0;
|
||||||
/* NB: cli_sock_parse_request() may have put
|
cli_parse_request(appctx);
|
||||||
* another CLI_ST_O_* into appctx->st0.
|
chunk_reset(appctx->chunk);
|
||||||
*/
|
/* NB: cli_sock_parse_request() may have put
|
||||||
|
* another CLI_ST_O_* into appctx->st0.
|
||||||
|
*/
|
||||||
|
|
||||||
appctx->st1 &= ~APPCTX_CLI_ST1_PAYLOAD;
|
appctx->st1 &= ~APPCTX_CLI_ST1_PAYLOAD;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
char *last_arg;
|
||||||
/*
|
/*
|
||||||
* Look for the "payload start" pattern at the end of a line
|
* Look for the "payload start" pattern at the end of a line
|
||||||
* Its location is not remembered here, this is just to switch
|
* Its location is not remembered here, this is just to switch
|
||||||
* to a gathering mode.
|
* to a gathering mode.
|
||||||
|
* The pattern must start by << followed by 0
|
||||||
|
* to 7 characters, and finished by the end of
|
||||||
|
* the command (\n or ;).
|
||||||
*/
|
*/
|
||||||
if (strcmp(appctx->chunk->area + appctx->chunk->data - strlen(PAYLOAD_PATTERN), PAYLOAD_PATTERN) == 0) {
|
/* look for the first space starting by the end of the line */
|
||||||
appctx->st1 |= APPCTX_CLI_ST1_PAYLOAD;
|
for (last_arg = appctx->chunk->area + appctx->chunk->data; last_arg != appctx->chunk->area; last_arg--) {
|
||||||
appctx->chunk->data++; // keep the trailing \0 after '<<'
|
if (*last_arg == ' ' || *last_arg == '\t') {
|
||||||
|
last_arg++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (strncmp(last_arg, PAYLOAD_PATTERN, strlen(PAYLOAD_PATTERN)) == 0) {
|
||||||
|
ssize_t pat_len = strlen(last_arg + strlen(PAYLOAD_PATTERN));
|
||||||
|
|
||||||
|
/* A customized pattern can't be more than 7 characters
|
||||||
|
* if it's more, don't make it a payload
|
||||||
|
*/
|
||||||
|
if (pat_len < sizeof(appctx->cli_payload_pat)) {
|
||||||
|
appctx->st1 |= APPCTX_CLI_ST1_PAYLOAD;
|
||||||
|
/* copy the customized pattern, don't store the << */
|
||||||
|
strncpy(appctx->cli_payload_pat, last_arg + strlen(PAYLOAD_PATTERN), sizeof(appctx->cli_payload_pat)-1);
|
||||||
|
appctx->cli_payload_pat[sizeof(appctx->cli_payload_pat)-1] = '\0';
|
||||||
|
appctx->chunk->data++; // keep the trailing \0 after the pattern
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* no payload, the command is complete: parse the request */
|
/* no payload, the command is complete: parse the request */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user