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$")
#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
......@@ -80,6 +79,8 @@ struct varnish {
struct VSM_data *vd;
};
#define NONSENSE "%XJEIFLH|)Xspa8P"
static VTAILQ_HEAD(, varnish) varnishes =
VTAILQ_HEAD_INITIALIZER(varnishes);
......@@ -117,28 +118,6 @@ varnish_ask_cli(const struct varnish *v, const char *cmd, char **repl)
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
*/
......@@ -523,10 +502,8 @@ varnish_vcl(struct varnish *v, const char *vcl, enum cli_status_e expect)
vsb = vsb_newauto();
AN(vsb);
v->vcl_nbr++;
vsb_printf(vsb, "vcl.inline vcl%d \"", v->vcl_nbr);
varnish_cli_encode(vsb, vcl);
vsb_printf(vsb, "\"", *vcl);
vsb_printf(vsb, "vcl.inline vcl%d << %s\n%s\n%s\n",
++v->vcl_nbr, NONSENSE, vcl, NONSENSE);
vsb_finish(vsb);
AZ(vsb_overflowed(vsb));
......@@ -575,14 +552,8 @@ varnish_vclbackend(struct varnish *v, const char *vcl)
vsb_finish(vsb2);
AZ(vsb_overflowed(vsb2));
v->vcl_nbr++;
vsb_printf(vsb, "vcl.inline vcl%d \"", v->vcl_nbr);
varnish_cli_encode(vsb, vsb_data(vsb2));
varnish_cli_encode(vsb, vcl);
vsb_printf(vsb, "\"", *vcl);
vsb_printf(vsb, "vcl.inline vcl%d << %s\n%s\n%s\n%s\n",
++v->vcl_nbr, NONSENSE, vsb_data(vsb2), vcl, NONSENSE);
vsb_finish(vsb);
AZ(vsb_overflowed(vsb));
......
......@@ -37,7 +37,7 @@ struct cli {
#define CLI_MAGIC 0x4038d570
struct vsb *sb;
enum cli_status_e result;
const char *cmd;
char *cmd;
unsigned auth;
char challenge[34];
char *ident;
......
......@@ -68,6 +68,9 @@ struct cls_fd {
struct cli *cli, clis;
cls_cb_f *closefunc;
void *priv;
struct vsb *last_arg;
int last_idx;
char **argv;
};
struct cls {
......@@ -234,13 +237,12 @@ cls_dispatch(struct cli *cli, struct cli_proto *clp, char * const * av,
*/
static int
cls_vlu(void *priv, const char *p)
cls_vlu2(void *priv, char * const *av)
{
struct cls_fd *cfd;
struct cls *cs;
struct cls_func *cfn;
struct cli *cli;
char * * av;
unsigned na;
CAST_OBJ_NOTNULL(cfd, priv, CLS_FD_MAGIC);
......@@ -249,23 +251,10 @@ cls_vlu(void *priv, const char *p)
cli = cfd->cli;
CHECK_OBJ_NOTNULL(cli, CLI_MAGIC);
AZ(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);
AN(cli->cmd);
cli->cmd = p;
cli->cls = cs;
av = ParseArgv(p, 0);
AN(av);
cli->result = CLIS_UNKNOWN;
vsb_clear(cli->sb);
cli_out(cli, "Unknown request.\nType 'help' for more info.\n");
......@@ -306,9 +295,7 @@ cls_vlu(void *priv, const char *p)
if (cs->after != NULL)
cs->after(cli);
cli->cmd = NULL;
cli->cls = NULL;
FreeArgv(av);
if (cli_writeres(cfd->fdo, cli) || cli->result == CLIS_CLOSE)
return (1);
......@@ -316,6 +303,82 @@ cls_vlu(void *priv, const char *p)
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 *
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