[master] e0b9077 Add support for JSON CLI responses.
Poul-Henning Kamp
phk at FreeBSD.org
Thu Feb 4 02:55:26 CET 2016
commit e0b9077c87b683a12af45daaf8c08ab4e7ce4195
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date: Thu Feb 4 01:51:05 2016 +0000
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
diff --git a/bin/varnishd/cache/cache_cli.c b/bin/varnishd/cache/cache_cli.c
index 3ba8cdd..bc2302e 100644
--- a/bin/varnishd/cache/cache_cli.c
+++ b/bin/varnishd/cache/cache_cli.c
@@ -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 }
};
diff --git a/bin/varnishd/mgt/mgt_cli.c b/bin/varnishd/mgt/mgt_cli.c
index baae752..6df8f9e 100644
--- a/bin/varnishd/mgt/mgt_cli.c
+++ b/bin/varnishd/mgt/mgt_cli.c
@@ -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 },
diff --git a/bin/varnishtest/tests/b00008.vtc b/bin/varnishtest/tests/b00008.vtc
index 2448aa4..ac18701 100644
--- a/bin/varnishtest/tests/b00008.vtc
+++ b/bin/varnishtest/tests/b00008.vtc
@@ -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"
diff --git a/include/vcli_priv.h b/include/vcli_priv.h
index 2f98d7d..61f5720 100644
--- a/include/vcli_priv.h
+++ b/include/vcli_priv.h
@@ -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);
diff --git a/include/vcli_serve.h b/include/vcli_serve.h
index fe240c1..0ff65d0 100644
--- a/include/vcli_serve.h
+++ b/include/vcli_serve.h
@@ -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;
diff --git a/include/vsb.h b/include/vsb.h
index 4b34314..a3bdd3d 100644
--- a/include/vsb.h
+++ b/include/vsb.h
@@ -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
diff --git a/lib/libvarnish/cli_common.c b/lib/libvarnish/cli_common.c
index 44a6869..b735d1f 100644
--- a/lib/libvarnish/cli_common.c
+++ b/lib/libvarnish/cli_common.c
@@ -84,6 +84,31 @@ VCLI_Overflow(struct cli *cli)
/*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)
{
diff --git a/lib/libvarnish/cli_serve.c b/lib/libvarnish/cli_serve.c
index 64fb7dd..9861e0c 100644
--- a/lib/libvarnish/cli_serve.c
+++ b/lib/libvarnish/cli_serve.c
@@ -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);
}
diff --git a/lib/libvarnish/vsb.c b/lib/libvarnish/vsb.c
index 4d80b8a..d737ef1 100644
--- a/lib/libvarnish/vsb.c
+++ b/lib/libvarnish/vsb.c
@@ -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
More information about the varnish-commit
mailing list