Commit e0b9077c authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Add support for JSON CLI responses.

To get JSON back, the first argument must be "-j".

Currently only "help -j" is implemented, but that
will helpfully tell you which commands support
json output.

All JSON output has the form:

	[ version#, [<cli_command>],
		stuff
	]

For instance:

	[ 1, ["help", "-j"],
	  {
	  "request": "help",
	  "syntax": "help [<command>]",
	  "help": "\tShow command/protocol help.",
	  "minarg": 0, "maxarg": 1, "flags": "", "json": true
	  },
	  {
	  "request": "ping",
	  "syntax": "ping [<timestamp>]",
	  "help": "\tKeep connection alive.",
	  "minarg": 0, "maxarg": 1, "flags": "", "json": false
	  },
	  ...
	]

The string quoting for weird characters in JSON is XXX incomplete.

Prodded for by:	Kristian
parent b616a4dd
......@@ -112,7 +112,7 @@ CLI_Run(void)
static struct cli_proto cli_cmds[] = {
{ CLI_PING, "i", VCLS_func_ping },
{ CLI_HELP, "i", VCLS_func_help },
{ CLI_HELP, "i", VCLS_func_help, VCLS_func_help_json, cli_cmds },
{ NULL }
};
......
......@@ -142,7 +142,9 @@ mcf_askchild(struct cli *cli, const char * const *av, void *priv)
*/
if (cli_o <= 0) {
if (!strcmp(av[1], "help")) {
VCLI_Out(cli, "No help from child, (not running).\n");
if (av[2] == NULL || strcmp(av[2], "-j"))
VCLI_Out(cli,
"No help from child, (not running).\n");
return;
}
VCLI_SetResult(cli, CLIS_UNKNOWN);
......@@ -308,7 +310,7 @@ mcf_auth(struct cli *cli, const char *const *av, void *priv)
}
static struct cli_proto cli_auth[] = {
{ CLI_HELP, "", VCLS_func_help },
{ CLI_HELP, "", VCLS_func_help, VCLS_func_help_json },
{ CLI_PING, "", VCLS_func_ping },
{ CLI_AUTH, "", mcf_auth },
{ CLI_QUIT, "", VCLS_func_close },
......
......@@ -24,6 +24,8 @@ varnish v1 -start
varnish v1 -cliok "help"
varnish v1 -cliok "help -j"
varnish v1 -clierr 106 "param.set waiter HASH(0x8839c4c)"
varnish v1 -cliok "param.set cli_limit 128"
......
......@@ -48,12 +48,14 @@ struct cli_proto {
/* Dispatch information */
cli_func_t *func;
cli_func_t *jsonfunc;
void *priv;
};
/* The implementation must provide these functions */
int VCLI_Overflow(struct cli *cli);
void VCLI_Out(struct cli *cli, const char *fmt, ...)
__v_printflike(2, 3);
void VCLI_Out(struct cli *cli, const char *fmt, ...) __v_printflike(2, 3);
void VCLI_Quote(struct cli *cli, const char *str);
void VCLI_JSON_str(struct cli *cli, const char *str);
void VCLI_JSON_ver(struct cli *cli, unsigned ver, const char * const * av);
void VCLI_SetResult(struct cli *cli, unsigned r);
......@@ -42,4 +42,5 @@ void VCLS_Destroy(struct VCLS **);
/* From libvarnish/cli.c */
cli_func_t VCLS_func_close;
cli_func_t VCLS_func_help;
cli_func_t VCLS_func_help_json;
cli_func_t VCLS_func_ping;
......@@ -76,6 +76,7 @@ char *VSB_data(const struct vsb *);
ssize_t VSB_len(const struct vsb *);
void VSB_delete(struct vsb *);
#define VSB_QUOTE_NONL 1
#define VSB_QUOTE_JSON 2
void VSB_quote(struct vsb *s, const char *p, int len, int how);
void VSB_indent(struct vsb *, int);
#ifdef __cplusplus
......
......@@ -82,6 +82,31 @@ VCLI_Overflow(struct cli *cli)
return (0);
}
/*lint -e{818} cli could be const */
void
VCLI_JSON_str(struct cli *cli, const char *s)
{
CHECK_OBJ_NOTNULL(cli, CLI_MAGIC);
VSB_quote(cli->sb, s, -1, VSB_QUOTE_JSON);
}
/*lint -e{818} cli could be const */
void
VCLI_JSON_ver(struct cli *cli, unsigned ver, const char * const * av)
{
int i;
CHECK_OBJ_NOTNULL(cli, CLI_MAGIC);
VCLI_Out(cli, "[ %u, [", ver);
for (i = 1; av[i] != NULL; i++) {
VCLI_JSON_str(cli, av[i]);
if (av[i + 1] != NULL)
VCLI_Out(cli, ", ");
}
VCLI_Out(cli, "]");
}
/*lint -e{818} cli could be const */
void
VCLI_Quote(struct cli *cli, const char *s)
......
......@@ -146,7 +146,7 @@ VCLS_func_help(struct cli *cli, const char * const *av, void *priv)
}
for (u = 0; u < sizeof cp->flags; u++) {
if (cp->flags[u] == '*') {
cp->func(cli,av,priv);
cp->func(cli, av, NULL);
return;
}
}
......@@ -179,7 +179,7 @@ VCLS_func_help(struct cli *cli, const char * const *av, void *priv)
if (i)
continue;
if (wc) {
cp->func(cli, av, priv);
cp->func(cli, av, NULL);
continue;
}
if (debug != d)
......@@ -192,6 +192,57 @@ VCLS_func_help(struct cli *cli, const char * const *av, void *priv)
}
}
void
VCLS_func_help_json(struct cli *cli, const char * const *av, void *priv)
{
struct cli_proto *cp;
struct VCLS_func *cfn;
struct VCLS *cs;
unsigned u, f_wc, f_i;
(void)priv;
cs = cli->cls;
CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
if (priv == NULL)
VCLI_JSON_ver(cli, 1, av);
VTAILQ_FOREACH(cfn, &cs->funcs, list) {
if (cfn->auth > cli->auth)
continue;
for (cp = cfn->clp; cp->request != NULL; cp++) {
f_wc = f_i = 0;
for (u = 0; u < sizeof cp->flags; u++) {
if (cp->flags[u] == '*')
f_wc = 1;
if (cp->flags[u] == 'i')
f_i = 1;
}
if (f_wc) {
cp->func(cli, av, priv);
continue;
}
if (f_i)
continue;
VCLI_Out(cli, ",\n {");
VCLI_Out(cli, "\n \"request\": ");
VCLI_JSON_str(cli, cp->request);
VCLI_Out(cli, ",\n \"syntax\": ");
VCLI_JSON_str(cli, cp->syntax);
VCLI_Out(cli, ",\n \"help\": ");
VCLI_JSON_str(cli, cp->help);
VCLI_Out(cli, ",\n \"minarg\": %d", cp->minarg);
VCLI_Out(cli, ", \"maxarg\": %d", cp->maxarg);
VCLI_Out(cli, ", \"flags\": ");
VCLI_JSON_str(cli, cp->flags);
VCLI_Out(cli, ", \"json\": %s",
cp->jsonfunc == NULL ? "false" : "true");
VCLI_Out(cli, "\n }");
}
}
if (priv == NULL)
VCLI_Out(cli, "\n]\n");
}
/*--------------------------------------------------------------------
* Look for a CLI command to execute
*/
......@@ -201,6 +252,7 @@ cls_dispatch(struct cli *cli, struct cli_proto *clp, char * const * av,
unsigned ac)
{
struct cli_proto *cp;
int json = 0;
AN(av);
for (cp = clp; cp->request != NULL; cp++) {
......@@ -212,19 +264,27 @@ cls_dispatch(struct cli *cli, struct cli_proto *clp, char * const * av,
if (cp->request == NULL)
return (0);
if (cp->func == NULL) {
if (ac > 1 && !strcmp(av[2], "-j"))
json = 1;
if (cp->func == NULL && !json) {
VCLI_Out(cli, "Unimplemented\n");
VCLI_SetResult(cli, CLIS_UNIMPL);
return(1);
}
if (cp->jsonfunc == NULL && json) {
VCLI_Out(cli, "JSON unimplemented\n");
VCLI_SetResult(cli, CLIS_UNIMPL);
return(1);
}
if (ac - 1 < cp->minarg) {
if (ac - 1 < cp->minarg + json) {
VCLI_Out(cli, "Too few parameters\n");
VCLI_SetResult(cli, CLIS_TOOFEW);
return(1);
}
if (ac - 1> cp->maxarg) {
if (ac - 1> cp->maxarg + json) {
VCLI_Out(cli, "Too many parameters\n");
VCLI_SetResult(cli, CLIS_TOOMANY);
return(1);
......@@ -232,7 +292,10 @@ cls_dispatch(struct cli *cli, struct cli_proto *clp, char * const * av,
cli->result = CLIS_OK;
VSB_clear(cli->sb);
cp->func(cli, (const char * const *)av, cp->priv);
if (json)
cp->jsonfunc(cli, (const char * const *)av, cp->priv);
else
cp->func(cli, (const char * const *)av, cp->priv);
return (1);
}
......
......@@ -498,7 +498,6 @@ VSB_quote(struct vsb *s, const char *p, int len, int how)
const char *q;
int quote = 0;
(void)how; /* For future enhancements */
if (len == -1)
len = strlen(p);
......@@ -508,7 +507,7 @@ VSB_quote(struct vsb *s, const char *p, int len, int how)
break;
}
}
if (!quote) {
if (!quote && !(how & VSB_QUOTE_JSON)) {
(void)VSB_bcat(s, p, len);
return;
}
......@@ -536,6 +535,7 @@ VSB_quote(struct vsb *s, const char *p, int len, int how)
(void)VSB_cat(s, "\\t");
break;
default:
/* XXX: Implement VSB_QUOTE_JSON */
if (isgraph(*q))
(void)VSB_putc(s, *q);
else
......
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