[master] 9046707cb Add m00053.vtc: Test dynamic calls

Nils Goroll nils.goroll at uplex.de
Mon Feb 8 17:52:04 UTC 2021


commit 9046707cb701819fa85d145f24cd5a203f06471c
Author: Nils Goroll <nils.goroll at uplex.de>
Date:   Sat Feb 6 14:10:01 2021 +0100

    Add m00053.vtc: Test dynamic calls
    
    This test case checks dynamic calls, and, in particular, the runtime
    context checks and recursion detection. Recursions have to be caught at
    the first instance.
    
    Also test interop with the PRIV_TOP compile time restriction
    
    Ref #3498
    Ref 6d49b18f1a7ad612b3c9ba6b3a8a5704fe84ea61
    
    The test has been manually annotated with information regarding the
    results expted from VCCs call tree walk.
    
    Explanation:
    
    .called == call, but every walk counts (for instance, barbarbar can be
    reached twice, via bar and barbar)
    
    .nref == sum(refs): Each VCL ref gains a ref, and each call from a sub
    which is itself dynamic (has nref > called).

diff --git a/bin/varnishtest/tests/m00053.vtc b/bin/varnishtest/tests/m00053.vtc
new file mode 100644
index 000000000..68034edbc
--- /dev/null
+++ b/bin/varnishtest/tests/m00053.vtc
@@ -0,0 +1,194 @@
+varnishtest "VCL_SUB type basics"
+
+varnish v1 -vcl {
+	import std;
+	import debug;
+
+	backend dummy None;
+
+	# call: 1 ref: 5 + 1
+	sub foo {
+		set resp.http.it = "works";
+	}
+	# call: 1 ref: 1 + 1 (from bar walk)
+	sub barbar {
+		# called from bar only, must be marked dynamic
+		call barbarbar;
+	}
+	# call: 2 (1 from bar walk, 1 from barbar walk)
+	# ref: 2 + 1
+	sub barbarbar {
+		# 2nd level call from dynamic
+	}
+	# call: 0 ref: 1
+	sub bar {
+		set beresp.http.it = "works";
+		call barbar;
+	}
+	# call: 0 ref: 1
+	sub indirect {
+		debug.call(foo);
+	}
+	# call: 0 ref: 1
+	sub direct {
+		call foo;
+	}
+	# call: 0 ref: 2
+	sub recursive {
+		std.log("recursive called");
+		debug.call(recursive);
+	}
+	# call: 1 ref: 1
+	sub recursive_indirect {
+		std.log("recursive_indirect called");
+		debug.call(recursive_indirect);
+	}
+	# call: 1 ref: 1
+	sub rollback {
+		std.rollback(req);
+	}
+	# call: 0 ref: 1
+	sub priv_top {
+		debug.test_priv_top("only works on client side");
+	}
+
+	sub vcl_recv {
+		if (req.url == "/wrong") {
+			debug.call(foo);
+		}
+		if (req.url == "/recursive") {
+			debug.call(recursive);
+		}
+		if (req.url == "/recursive_indirect") {
+			call recursive_indirect;
+		}
+		if (req.url == "/priv_top") {
+			return (pass);
+		}
+		return (synth(200));
+	}
+	sub vcl_synth {
+		if (req.url == "/foo") {
+			debug.call(foo);
+		} else if (req.url == "/direct") {
+			debug.call(direct);
+		} else if (req.url == "/indirect") {
+			debug.call(indirect);
+		} else if (req.url == "/rollback") {
+			debug.call(rollback);
+		} else if (req.url == "/callthenrollback") {
+			debug.call(foo);
+			call rollback;
+			if (! resp.http.it) {
+				set resp.http.rolledback = true;
+			}
+			debug.call(foo);
+		} else if (req.url == "/checkwrong") {
+			synthetic(debug.check_call(bar));
+			set resp.status = 500;
+		}
+		return (deliver);
+	}
+	sub vcl_backend_fetch {
+		debug.call(priv_top);
+	}
+	sub vcl_backend_error {
+		# falling through to None backend would be success
+		set beresp.status = 200;
+		return (deliver);
+	}
+} -start
+
+client c1 {
+	txreq -url "/foo"
+	rxresp
+	expect resp.status == 200
+	expect resp.http.it == "works"
+
+	txreq -url "/direct"
+	rxresp
+	expect resp.status == 200
+	expect resp.http.it == "works"
+
+	txreq -url "/indirect"
+	rxresp
+	expect resp.status == 200
+	expect resp.http.it == "works"
+
+	txreq -url "/callthenrollback"
+	rxresp
+	expect resp.status == 200
+	expect resp.http.rolledback == "true"
+	expect resp.http.it == "works"
+
+	txreq -url "/wrong"
+	rxresp
+	expect resp.status == 503
+} -start
+logexpect l2 -v v1 -g vxid -q {ReqURL ~ "^/recursive$"} {
+	expect *  *	VCL_Log	"^recursive called"
+	fail add  *	VCL_Log	"^recursive called"
+	expect 0  =	VCL_Error	{^Recursive call to "sub recursive..}
+	expect 0  =	VCL_return	"^fail"
+	expect *  =	End
+	fail clear
+} -start
+client c2 {
+	txreq -url "/recursive"
+	rxresp
+	expect resp.status == 503
+} -start
+logexpect l3 -v v1 -g vxid -q {ReqURL ~ "^/recursive_indirect$"} {
+	expect *  *	VCL_Log	"^recursive_indirect called"
+	fail add  *	VCL_Log	"^recursive_indirect called"
+	expect 0  =	VCL_Error	{^Recursive call to "sub recursive_indirect..}
+	expect 0  =	VCL_return	"^fail"
+	expect *  =	End
+	fail clear
+} -start
+client c3 {
+	txreq -url "/recursive_indirect"
+	rxresp
+	expect resp.status == 503
+} -start
+client c4 {
+	txreq -url "/rollback"
+	rxresp
+	expect resp.status == 200
+} -start
+client c5 {
+	txreq -url "/checkwrong"
+	rxresp
+	expect resp.status == 500
+	expect resp.body == {Dynamic call to "sub bar{}" not allowed from here}
+} -start
+client c6 {
+	txreq -url "/priv_top"
+	rxresp
+	expect resp.status == 503
+} -start
+
+varnish v1 -errvcl {Impossible Subroutine('<vcl.inline>' Line 8 Pos 13)} {
+	import std;
+	import debug;
+
+	backend dummy None;
+
+	sub impossible {
+		set req.http.impossible = beresp.reason;
+	}
+	sub vcl_recv {
+		if (req.url == "/impossible") {
+			debug.call(impossible);
+		}
+	}
+}
+
+client c1 -wait
+client c2 -wait
+logexpect l2 -wait
+client c3 -wait
+logexpect l3 -wait
+client c4 -wait
+client c5 -wait
+client c6 -wait
diff --git a/vmod/vmod_debug.c b/vmod/vmod_debug.c
index 49dd3276c..9d2866de0 100644
--- a/vmod/vmod_debug.c
+++ b/vmod/vmod_debug.c
@@ -1295,3 +1295,17 @@ xyzzy_just_return_regex(VRT_CTX, VCL_REGEX r)
 	AN(r);
 	return (r);
 }
+
+/*---------------------------------------------------------------------*/
+
+VCL_VOID v_matchproto_(td_xyzzy_call)
+xyzzy_call(VRT_CTX, VCL_SUB sub)
+{
+	VRT_call(ctx, sub);
+}
+
+VCL_STRING v_matchproto_(td_xyzzy_check_call)
+xyzzy_check_call(VRT_CTX, VCL_SUB sub)
+{
+	return (VRT_check_call(ctx, sub));
+}
diff --git a/vmod/vmod_debug.vcc b/vmod/vmod_debug.vcc
index 8ee1f27cd..cff0a8867 100644
--- a/vmod/vmod_debug.vcc
+++ b/vmod/vmod_debug.vcc
@@ -323,3 +323,12 @@ Test if the argument is a valid header according to RFC7230 section 3.2.
 $Function REGEX just_return_regex(REGEX)
 
 Take a REGEX argument and return it.
+
+$Function STRING check_call(SUB)
+
+Check if a sub can be called. Returns the NULL string if yes, or a
+string saying why not.
+
+$Function VOID call(SUB)
+
+Call a sub


More information about the varnish-commit mailing list