[master] 955fe07 Implement sparse/named arguments to VMOD functions.

Poul-Henning Kamp phk at FreeBSD.org
Tue Nov 25 14:50:43 CET 2014


commit 955fe0755b6626641ae4a45bf8ed5728eda8e851
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Tue Nov 25 13:49:32 2014 +0000

    Implement sparse/named arguments to VMOD functions.
    
    For now it probably only works with things like STRING and REAL.

diff --git a/bin/varnishtest/tests/m00019.vtc b/bin/varnishtest/tests/m00019.vtc
new file mode 100644
index 0000000..6dd8722
--- /dev/null
+++ b/bin/varnishtest/tests/m00019.vtc
@@ -0,0 +1,57 @@
+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");
+	}
+}
diff --git a/lib/libvcc/vcc_expr.c b/lib/libvcc/vcc_expr.c
index 54c113a..4c0f5ac 100644
--- a/lib/libvcc/vcc_expr.c
+++ b/lib/libvcc/vcc_expr.c
@@ -579,14 +579,64 @@ struct func_arg {
 };
 
 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, ')');
+
 }
 
 /*--------------------------------------------------------------------
diff --git a/lib/libvmod_debug/vmod.vcc b/lib/libvmod_debug/vmod.vcc
index 468fc51..902f724 100644
--- a/lib/libvmod_debug/vmod.vcc
+++ b/lib/libvmod_debug/vmod.vcc
@@ -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")
diff --git a/lib/libvmod_debug/vmod_debug.c b/lib/libvmod_debug/vmod_debug.c
index 08b5aa8..fba8d52 100644
--- a/lib/libvmod_debug/vmod_debug.c
+++ b/lib/libvmod_debug/vmod_debug.c
@@ -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);
+}



More information about the varnish-commit mailing list