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 */
|
||||
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 */
|
||||
char cli_payload_pat[8]; /* Payload pattern */
|
||||
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 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)
|
||||
break;
|
||||
|
||||
if (strcmp(p, PAYLOAD_PATTERN) == 0) {
|
||||
/* payload pattern recognized here, this is not an arg anymore,
|
||||
* the payload starts at the first byte that follows the zero
|
||||
* after the pattern.
|
||||
*/
|
||||
payload = p + strlen(PAYLOAD_PATTERN) + 1;
|
||||
break;
|
||||
/* first check if the '<<' is present, but this is not enough
|
||||
* because we don't know if this is the end of the string */
|
||||
if (strncmp(p, PAYLOAD_PATTERN, strlen(PAYLOAD_PATTERN)) == 0) {
|
||||
int pat_len = strlen(appctx->cli_payload_pat);
|
||||
|
||||
/* then if the customized pattern is empty, check if the next character is '\0' */
|
||||
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;
|
||||
@ -1010,29 +1019,53 @@ static void cli_io_handler(struct appctx *appctx)
|
||||
appctx->st0 = CLI_ST_PROMPT;
|
||||
|
||||
if (appctx->st1 & APPCTX_CLI_ST1_PAYLOAD) {
|
||||
/* empty line */
|
||||
if (!len) {
|
||||
/* remove the last two \n */
|
||||
appctx->chunk->data -= 2;
|
||||
appctx->chunk->area[appctx->chunk->data] = 0;
|
||||
cli_parse_request(appctx);
|
||||
chunk_reset(appctx->chunk);
|
||||
/* NB: cli_sock_parse_request() may have put
|
||||
* another CLI_ST_O_* into appctx->st0.
|
||||
*/
|
||||
/* look for a pattern */
|
||||
if (len == strlen(appctx->cli_payload_pat)) {
|
||||
/* here use 'len' because str still contains the \n */
|
||||
if (strncmp(str, appctx->cli_payload_pat, len) == 0) {
|
||||
/* remove the last two \n */
|
||||
appctx->chunk->data -= strlen(appctx->cli_payload_pat) + 2;
|
||||
appctx->chunk->area[appctx->chunk->data] = 0;
|
||||
cli_parse_request(appctx);
|
||||
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 {
|
||||
char *last_arg;
|
||||
/*
|
||||
* Look for the "payload start" pattern at the end of a line
|
||||
* Its location is not remembered here, this is just to switch
|
||||
* 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) {
|
||||
appctx->st1 |= APPCTX_CLI_ST1_PAYLOAD;
|
||||
appctx->chunk->data++; // keep the trailing \0 after '<<'
|
||||
/* look for the first space starting by the end of the line */
|
||||
for (last_arg = appctx->chunk->area + appctx->chunk->data; last_arg != appctx->chunk->area; last_arg--) {
|
||||
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 {
|
||||
/* no payload, the command is complete: parse the request */
|
||||
|
Loading…
x
Reference in New Issue
Block a user