Commit 3bc404ec authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Add a new feature to the CLI syntax: Bourne-shell like "here" documents.

The last argument to any CLI command can use this feature.

Typical example:

	vcl.inline vcl_new << 42
	backend foo {...}
	sub vcl_recv {...}
	42

The advantage is that no escaping is needed, as long as the magic
marker, in this case "42" does not match any line anywhere in the 
lines that make up the argument.

Arguments encoded this way are not subject to the "cli_buffer"
parameters size limitation.



git-svn-id: http://www.varnish-cache.org/svn/trunk/varnish-cache@5588 d4fa192b-c00b-0410-8231-f00ffab90ce4
parent f337dce4
...@@ -33,7 +33,6 @@ SVNID("$Id$") ...@@ -33,7 +33,6 @@ SVNID("$Id$")
#include <stdio.h> #include <stdio.h>
#include <ctype.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
...@@ -80,6 +79,8 @@ struct varnish { ...@@ -80,6 +79,8 @@ struct varnish {
struct VSM_data *vd; struct VSM_data *vd;
}; };
#define NONSENSE "%XJEIFLH|)Xspa8P"
static VTAILQ_HEAD(, varnish) varnishes = static VTAILQ_HEAD(, varnish) varnishes =
VTAILQ_HEAD_INITIALIZER(varnishes); VTAILQ_HEAD_INITIALIZER(varnishes);
...@@ -117,28 +118,6 @@ varnish_ask_cli(const struct varnish *v, const char *cmd, char **repl) ...@@ -117,28 +118,6 @@ varnish_ask_cli(const struct varnish *v, const char *cmd, char **repl)
return ((enum cli_status_e)retval); return ((enum cli_status_e)retval);
} }
static void
varnish_cli_encode(struct vsb *vsb, const char *str)
{
for (; *str != '\0'; str++) {
switch (*str) {
case '\\':
case '"':
vsb_printf(vsb, "\\%c", *str); break;
case '\n':
vsb_printf(vsb, "\\n"); break;
case '\t':
vsb_printf(vsb, "\\t"); break;
default:
if (isgraph(*str) || *str == ' ')
vsb_putc(vsb, *str);
else
vsb_printf(vsb, "\\x%02x", *str);
}
}
}
/********************************************************************** /**********************************************************************
* Allocate and initialize a varnish * Allocate and initialize a varnish
*/ */
...@@ -523,10 +502,8 @@ varnish_vcl(struct varnish *v, const char *vcl, enum cli_status_e expect) ...@@ -523,10 +502,8 @@ varnish_vcl(struct varnish *v, const char *vcl, enum cli_status_e expect)
vsb = vsb_newauto(); vsb = vsb_newauto();
AN(vsb); AN(vsb);
v->vcl_nbr++; vsb_printf(vsb, "vcl.inline vcl%d << %s\n%s\n%s\n",
vsb_printf(vsb, "vcl.inline vcl%d \"", v->vcl_nbr); ++v->vcl_nbr, NONSENSE, vcl, NONSENSE);
varnish_cli_encode(vsb, vcl);
vsb_printf(vsb, "\"", *vcl);
vsb_finish(vsb); vsb_finish(vsb);
AZ(vsb_overflowed(vsb)); AZ(vsb_overflowed(vsb));
...@@ -575,14 +552,8 @@ varnish_vclbackend(struct varnish *v, const char *vcl) ...@@ -575,14 +552,8 @@ varnish_vclbackend(struct varnish *v, const char *vcl)
vsb_finish(vsb2); vsb_finish(vsb2);
AZ(vsb_overflowed(vsb2)); AZ(vsb_overflowed(vsb2));
v->vcl_nbr++; vsb_printf(vsb, "vcl.inline vcl%d << %s\n%s\n%s\n%s\n",
vsb_printf(vsb, "vcl.inline vcl%d \"", v->vcl_nbr); ++v->vcl_nbr, NONSENSE, vsb_data(vsb2), vcl, NONSENSE);
varnish_cli_encode(vsb, vsb_data(vsb2));
varnish_cli_encode(vsb, vcl);
vsb_printf(vsb, "\"", *vcl);
vsb_finish(vsb); vsb_finish(vsb);
AZ(vsb_overflowed(vsb)); AZ(vsb_overflowed(vsb));
......
...@@ -37,7 +37,7 @@ struct cli { ...@@ -37,7 +37,7 @@ struct cli {
#define CLI_MAGIC 0x4038d570 #define CLI_MAGIC 0x4038d570
struct vsb *sb; struct vsb *sb;
enum cli_status_e result; enum cli_status_e result;
const char *cmd; char *cmd;
unsigned auth; unsigned auth;
char challenge[34]; char challenge[34];
char *ident; char *ident;
......
...@@ -68,6 +68,9 @@ struct cls_fd { ...@@ -68,6 +68,9 @@ struct cls_fd {
struct cli *cli, clis; struct cli *cli, clis;
cls_cb_f *closefunc; cls_cb_f *closefunc;
void *priv; void *priv;
struct vsb *last_arg;
int last_idx;
char **argv;
}; };
struct cls { struct cls {
...@@ -234,13 +237,12 @@ cls_dispatch(struct cli *cli, struct cli_proto *clp, char * const * av, ...@@ -234,13 +237,12 @@ cls_dispatch(struct cli *cli, struct cli_proto *clp, char * const * av,
*/ */
static int static int
cls_vlu(void *priv, const char *p) cls_vlu2(void *priv, char * const *av)
{ {
struct cls_fd *cfd; struct cls_fd *cfd;
struct cls *cs; struct cls *cs;
struct cls_func *cfn; struct cls_func *cfn;
struct cli *cli; struct cli *cli;
char * * av;
unsigned na; unsigned na;
CAST_OBJ_NOTNULL(cfd, priv, CLS_FD_MAGIC); CAST_OBJ_NOTNULL(cfd, priv, CLS_FD_MAGIC);
...@@ -249,23 +251,10 @@ cls_vlu(void *priv, const char *p) ...@@ -249,23 +251,10 @@ cls_vlu(void *priv, const char *p)
cli = cfd->cli; cli = cfd->cli;
CHECK_OBJ_NOTNULL(cli, CLI_MAGIC); CHECK_OBJ_NOTNULL(cli, CLI_MAGIC);
AZ(cli->cmd); AN(cli->cmd);
/*
* Lines with only whitespace are simply ignored, in order to not
* complicate CLI-client side scripts and TELNET users
*/
for (; isspace(*p); p++)
continue;
if (*p == '\0')
return (0);
cli->cmd = p;
cli->cls = cs; cli->cls = cs;
av = ParseArgv(p, 0);
AN(av);
cli->result = CLIS_UNKNOWN; cli->result = CLIS_UNKNOWN;
vsb_clear(cli->sb); vsb_clear(cli->sb);
cli_out(cli, "Unknown request.\nType 'help' for more info.\n"); cli_out(cli, "Unknown request.\nType 'help' for more info.\n");
...@@ -306,9 +295,7 @@ cls_vlu(void *priv, const char *p) ...@@ -306,9 +295,7 @@ cls_vlu(void *priv, const char *p)
if (cs->after != NULL) if (cs->after != NULL)
cs->after(cli); cs->after(cli);
cli->cmd = NULL;
cli->cls = NULL; cli->cls = NULL;
FreeArgv(av);
if (cli_writeres(cfd->fdo, cli) || cli->result == CLIS_CLOSE) if (cli_writeres(cfd->fdo, cli) || cli->result == CLIS_CLOSE)
return (1); return (1);
...@@ -316,6 +303,82 @@ cls_vlu(void *priv, const char *p) ...@@ -316,6 +303,82 @@ cls_vlu(void *priv, const char *p)
return (0); return (0);
} }
static int
cls_vlu(void *priv, const char *p)
{
struct cls_fd *cfd;
struct cli *cli;
int i;
char **av;
CAST_OBJ_NOTNULL(cfd, priv, CLS_FD_MAGIC);
cli = cfd->cli;
CHECK_OBJ_NOTNULL(cli, CLI_MAGIC);
if (cfd->argv == NULL) {
/*
* Lines with only whitespace are simply ignored, in order
* to not complicate CLI-client side scripts and TELNET users
*/
for (; isspace(*p); p++)
continue;
if (*p == '\0')
return (0);
REPLACE(cli->cmd, p);
av = ParseArgv(p, 0);
AN(av);
if (av[0] != NULL) {
i = cls_vlu2(priv, av);
FreeArgv(av);
free(cli->cmd);
cli->cmd = NULL;
return (i);
}
for (i = 1; av[i] != NULL; i++)
continue;
if (i < 3 || strcmp(av[i - 2], "<<")) {
i = cls_vlu2(priv, av);
FreeArgv(av);
free(cli->cmd);
cli->cmd = NULL;
return (i);
}
cfd->argv = av;
cfd->last_idx = i - 2;
cfd->last_arg = vsb_newauto();
AN(cfd->last_arg);
return (0);
} else {
AN(cfd->argv[cfd->last_idx]);
assert(!strcmp(cfd->argv[cfd->last_idx], "<<"));
AN(cfd->argv[cfd->last_idx + 1]);
if (strcmp(p, cfd->argv[cfd->last_idx + 1])) {
vsb_cat(cfd->last_arg, p);
vsb_cat(cfd->last_arg, "\n");
return (0);
}
vsb_finish(cfd->last_arg);
AZ(vsb_overflowed(cfd->last_arg));
free(cfd->argv[cfd->last_idx]);
cfd->argv[cfd->last_idx] = NULL;
free(cfd->argv[cfd->last_idx + 1]);
cfd->argv[cfd->last_idx + 1] = NULL;
cfd->argv[cfd->last_idx] = vsb_data(cfd->last_arg);
i = cls_vlu2(priv, cfd->argv);
cfd->argv[cfd->last_idx] = NULL;
FreeArgv(cfd->argv);
cfd->argv = NULL;
free(cli->cmd);
cli->cmd = NULL;
vsb_delete(cfd->last_arg);
cfd->last_arg = NULL;
cfd->last_idx = 0;
return (i);
}
}
struct cls * struct cls *
CLS_New(cls_cbc_f *before, cls_cbc_f *after, unsigned maxlen) CLS_New(cls_cbc_f *before, cls_cbc_f *after, unsigned maxlen)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment