Commit 955fe075 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Implement sparse/named arguments to VMOD functions.

For now it probably only works with things like STRING and REAL.
parent 9bad2653
varnishtest "Test var args"
server s1 {
rxreq
txresp -bodylen 6
} -start
varnish v1 -vcl+backend {
import ${vmod_debug};
sub vcl_deliver {
set resp.http.foo1 = debug.argtest("1", 2.0, "3");
set resp.http.foo2 = debug.argtest("1", two = 2.0, three = "3");
set resp.http.foo3 = debug.argtest("1", three = "3", two = 2.0);
set resp.http.foo4 = debug.argtest("1", 2.0, three = "3");
set resp.http.foo5 = debug.argtest("1", 2.0);
set resp.http.foo6 = debug.argtest("1");
}
} -start
client c1 {
txreq
rxresp
expect resp.bodylen == "6"
expect resp.http.foo1 == "1 2 3"
expect resp.http.foo2 == "1 2 3"
expect resp.http.foo3 == "1 2 3"
expect resp.http.foo4 == "1 2 3"
expect resp.http.foo5 == "1 2 3"
expect resp.http.foo6 == "1 2 3"
} -run
delay .1
varnish v1 -errvcl {Argument 'one' already used} {
import ${vmod_debug};
backend b1 {.host = "127.0.0.1";}
sub vcl_deliver {
set resp.http.foo5 = debug.argtest("1", one = "1");
}
}
varnish v1 -errvcl {Argument 'one' missing} {
import ${vmod_debug};
backend b1 {.host = "127.0.0.1";}
sub vcl_deliver {
set resp.http.foo5 = debug.argtest(two = 2.0, three = "3");
}
}
varnish v1 -errvcl {Unknown argument 'four'} {
import ${vmod_debug};
backend b1 {.host = "127.0.0.1";}
sub vcl_deliver {
set resp.http.foo5 = debug.argtest("1", two = 2.0, four = "3");
}
}
......@@ -578,15 +578,65 @@ struct func_arg {
VTAILQ_ENTRY(func_arg) list;
};
static void
vcc_do_arg(struct vcc *tl, struct func_arg *fa)
{
const char *p, *r;
struct expr *e2;
if (fa->type == ENUM) {
ExpectErr(tl, ID);
ERRCHK(tl);
r = p = fa->enum_bits;
do {
if (vcc_IdIs(tl->t, p))
break;
p += strlen(p) + 1;
} while (*p != '\0');
if (*p == '\0') {
VSB_printf(tl->sb, "Wrong enum value.");
VSB_printf(tl->sb, " Expected one of:\n");
do {
VSB_printf(tl->sb, "\t%s\n", r);
r += strlen(r) + 1;
} while (*r != '\0');
vcc_ErrWhere(tl, tl->t);
return;
}
fa->result = vcc_mk_expr(VOID, "\"%.*s\"", PF(tl->t));
SkipToken(tl, ID);
} else {
vcc_expr0(tl, &e2, fa->type);
ERRCHK(tl);
if (e2->fmt != fa->type) {
VSB_printf(tl->sb, "Wrong argument type.");
VSB_printf(tl->sb, " Expected %s.",
vcc_Type(fa->type));
VSB_printf(tl->sb, " Got %s.\n",
vcc_Type(e2->fmt));
vcc_ErrWhere2(tl, e2->t1, tl->t);
return;
}
assert(e2->fmt == fa->type);
if (e2->fmt == STRING_LIST) {
e2 = vcc_expr_edit(STRING_LIST,
"\v+\n\v1,\nvrt_magic_string_end\v-",
e2, NULL);
}
fa->result = e2;
}
}
static void
vcc_func(struct vcc *tl, struct expr **e, const char *cfunc,
const char *extra, const char *name, const char *args)
{
const char *p, *r;
struct expr *e1, *e2;
const char *p;
struct expr *e1;
struct func_arg *fa, *fa2;
enum var_type rfmt;
VTAILQ_HEAD(,func_arg) head;
struct token *t1;
AN(cfunc);
AN(args);
......@@ -625,63 +675,68 @@ vcc_func(struct vcc *tl, struct expr **e, const char *cfunc,
}
VTAILQ_FOREACH(fa, &head, list) {
if (tl->t->tok == ')')
break;
if (fa->result != NULL)
continue;
e2 = NULL;
if (fa->type == ENUM) {
ExpectErr(tl, ID);
ERRCHK(tl);
r = p = fa->enum_bits;
do {
if (vcc_IdIs(tl->t, p))
break;
p += strlen(p) + 1;
} while (*p != '\0');
if (*p == '\0') {
VSB_printf(tl->sb, "Wrong enum value.");
VSB_printf(tl->sb, " Expected one of:\n");
do {
VSB_printf(tl->sb, "\t%s\n", r);
r += strlen(r) + 1;
} while (*r != '\0');
vcc_ErrWhere(tl, tl->t);
return;
}
fa->result = vcc_mk_expr(VOID, "\"%.*s\"", PF(tl->t));
SkipToken(tl, ID);
} else {
vcc_expr0(tl, &e2, fa->type);
ERRCHK(tl);
if (e2->fmt != fa->type) {
VSB_printf(tl->sb, "Wrong argument type.");
VSB_printf(tl->sb, " Expected %s.",
vcc_Type(fa->type));
VSB_printf(tl->sb, " Got %s.\n",
vcc_Type(e2->fmt));
vcc_ErrWhere2(tl, e2->t1, tl->t);
return;
}
assert(e2->fmt == fa->type);
if (e2->fmt == STRING_LIST) {
e2 = vcc_expr_edit(STRING_LIST,
"\v+\n\v1,\nvrt_magic_string_end\v-",
e2, NULL);
}
fa->result = e2;
if (tl->t->tok == ID) {
t1 = VTAILQ_NEXT(tl->t, list);
if (t1->tok == '=')
break;
}
if (VTAILQ_NEXT(fa, list) != NULL)
SkipToken(tl, ',');
vcc_do_arg(tl, fa);
ERRCHK(tl);
if (tl->t->tok == ')')
break;
SkipToken(tl, ',');
}
while (tl->t->tok == ID) {
VTAILQ_FOREACH(fa, &head, list) {
if (fa->name == NULL)
continue;
if (vcc_IdIs(tl->t, fa->name))
break;
}
if (fa == NULL) {
VSB_printf(tl->sb, "Unknown argument '%.*s'\n",
PF(tl->t));
vcc_ErrWhere(tl, tl->t);
return;
}
if (fa->result != NULL) {
VSB_printf(tl->sb, "Argument '%s' already used\n",
fa->name);
vcc_ErrWhere(tl, tl->t);
return;
}
vcc_NextToken(tl);
SkipToken(tl, '=');
vcc_do_arg(tl, fa);
ERRCHK(tl);
if (tl->t->tok == ')')
break;
SkipToken(tl, ',');
}
SkipToken(tl, ')');
e1 = vcc_mk_expr(rfmt, "%s(ctx%s\v+", cfunc, extra);
VTAILQ_FOREACH_SAFE(fa, &head, list, fa2) {
AN(fa->result);
e1 = vcc_expr_edit(e1->fmt, "\v1,\n\v2", e1, fa->result);
if (fa->result == NULL && fa->val != NULL)
fa->result = vcc_mk_expr(fa->type, "%s", fa->val);
if (fa->result != NULL)
e1 = vcc_expr_edit(e1->fmt, "\v1,\n\v2",
e1, fa->result);
else {
VSB_printf(tl->sb, "Argument '%s' missing\n",
fa->name);
vcc_ErrWhere(tl, tl->t);
}
free(fa);
}
e1 = vcc_expr_edit(e1->fmt, "\v1\n)\v-", e1, NULL);
*e = e1;
SkipToken(tl, ')');
}
/*--------------------------------------------------------------------
......
......@@ -39,7 +39,7 @@ $Function VOID panic(STRING_LIST)
Don't.
$Function STRING author(ENUM { phk, des, kristian, mithrandir } person)
$Function STRING author(ENUM { phk, des, kristian, mithrandir } person = "phk")
Test function for ENUM arguments
......@@ -59,7 +59,7 @@ $Function STRING test_priv_sess(PRIV_SESS, STRING)
Test function for SESS private pointers
$Function BLOB str2blob(STRING src)
$Function BLOB str2blob(STRING src = "foo")
Turn a string into a blob
......@@ -89,7 +89,9 @@ $Method TIME .date()
You never know when you need a date.
$Function VOID rot52(HTTP)
$Function VOID rot52(HTTP hdr)
Encrypt the HTTP header with quad-ROT13 encryption,
(this is approx 33% better than triple-DES).
$Function STRING argtest(STRING one, REAL two = 2, STRING three = "3")
......@@ -171,3 +171,12 @@ vmod_rot52(VRT_CTX, VCL_HTTP hp)
http_PrintfHeader(hp, "Encrypted: ROT52");
}
VCL_STRING
vmod_argtest(VRT_CTX, VCL_STRING one, VCL_REAL two, VCL_STRING three)
{
char buf[100];
bprintf(buf, "%s %g %s", one, two, three);
return WS_Copy(ctx->ws, buf, -1);
}
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