[master] 61a15cb Implement premature VCL failure in vcl_recv{} and vcl_synth{}

Poul-Henning Kamp phk at FreeBSD.org
Mon Feb 6 10:24:05 CET 2017


commit 61a15cbffe1141c13b87e30d48ce1402f84433bf
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Mon Feb 6 09:22:52 2017 +0000

    Implement premature VCL failure in vcl_recv{} and vcl_synth{}

diff --git a/bin/varnishd/cache/cache_req_fsm.c b/bin/varnishd/cache/cache_req_fsm.c
index e70fec3..b24159b 100644
--- a/bin/varnishd/cache/cache_req_fsm.c
+++ b/bin/varnishd/cache/cache_req_fsm.c
@@ -140,6 +140,26 @@ cnt_deliver(struct worker *wrk, struct req *req)
 }
 
 /*--------------------------------------------------------------------
+ * VCL failed, die horribly
+ */
+
+static enum req_fsm_nxt
+cnt_vclfail(const struct worker *wrk, struct req *req)
+{
+
+	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
+	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
+
+	HTTP_Copy(req->http, req->http0);
+	WS_Reset(req->ws, req->ws_req);
+	req->err_code = 503;
+	req->err_reason = "VCL failed";
+	req->req_step = R_STP_SYNTH;
+	req->doclose = SC_VCL_FAILURE;
+	return (REQ_FSM_MORE);
+}
+
+/*--------------------------------------------------------------------
  * Emit a synthetic response
  */
 
@@ -177,14 +197,19 @@ cnt_synth(struct worker *wrk, struct req *req)
 
 	AZ(VSB_finish(synth_body));
 
-	http_Unset(h, H_Content_Length);
-	http_PrintfHeader(req->resp, "Content-Length: %zd",
-	    VSB_len(synth_body));
-
-	/* Discard any lingering request body before delivery */
-	(void)VRB_Ignore(req);
+	if (wrk->handling == VCL_RET_FAIL) {
+		VSB_destroy(&synth_body);
+		req->doclose = SC_VCL_FAILURE;
+		VSLb_ts_req(req, "Resp", W_TIM_real(wrk));
+		http_Teardown(req->resp);
+		return (REQ_FSM_DONE);
+	}
 
 	if (wrk->handling == VCL_RET_RESTART) {
+		/*
+		 * XXX: Should we reset req->doclose = SC_VCL_FAILURE
+		 * XXX: If so, to what ?
+		 */
 		HTTP_Setup(h, req->ws, req->vsl, SLT_RespMethod);
 		VSB_destroy(&synth_body);
 		req->req_step = R_STP_RESTART;
@@ -192,6 +217,13 @@ cnt_synth(struct worker *wrk, struct req *req)
 	}
 	assert(wrk->handling == VCL_RET_DELIVER);
 
+	http_Unset(h, H_Content_Length);
+	http_PrintfHeader(req->resp, "Content-Length: %zd",
+	    VSB_len(synth_body));
+
+	/* Discard any lingering request body before delivery */
+	(void)VRB_Ignore(req);
+
 	req->objcore = HSH_Private(wrk);
 	CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
 	szl = -1;
@@ -754,6 +786,9 @@ cnt_recv(struct worker *wrk, struct req *req)
 	case VCL_RET_SYNTH:
 		req->req_step = R_STP_SYNTH;
 		return (REQ_FSM_MORE);
+	case VCL_RET_FAIL:
+		req->req_step = R_STP_VCLFAIL;
+		return (REQ_FSM_MORE);
 	default:
 		WRONG("Illegal return from vcl_recv{}");
 	}
diff --git a/bin/varnishtest/tests/v00051.vtc b/bin/varnishtest/tests/v00051.vtc
new file mode 100644
index 0000000..8800896
--- /dev/null
+++ b/bin/varnishtest/tests/v00051.vtc
@@ -0,0 +1,87 @@
+varnishtest "Test VCL failures"
+
+server s1 {
+	rxreq
+	txresp
+} -start
+
+varnish v1 -vcl+backend {
+	import debug;
+	sub vcl_recv {
+		if (req.http.foo == "bar") {
+			return(synth(748));
+		}
+		if (req.restarts == 0) {
+			debug.fail();
+		}
+	}
+	sub vcl_synth {
+		if (resp.status == 748) {
+			debug.fail();
+		}
+		if (req.restarts == 0 && req.http.foo == "foo") {
+			return (restart);
+		}
+	}
+} -start
+
+#######################################################################
+# Fail in vcl_recv, no handling in vcl_synth
+
+logexpect l1 -v v1 -g raw {
+	expect * 1001	VCL_call	"RECV"
+	expect 0 1001	Debug		"Forced failure"
+	expect 0 1001	VCL_return	"fail"
+} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 503
+	expect resp.reason == "VCL failed"
+} -run
+
+varnish v1 -expect sc_vcl_failure == 1
+
+logexpect l1 -wait
+
+#######################################################################
+# Fail in vcl_recv, vcl_synth restarts successfully
+
+logexpect l1 -v v1 -g raw {
+	expect * 1003	VCL_call	"RECV"
+	expect 0 1003	Debug		"Forced failure"
+	expect 0 1003	VCL_return	"fail"
+	expect * 1003	VCL_call	"SYNTH"
+	expect 0 1003	VCL_return	"restart"
+} -start
+
+client c1 {
+	txreq -hdr "foo: foo"
+	rxresp
+	expect resp.status == 200
+	expect resp.reason == "OK"
+} -run
+
+# NB: This is correct, req->doclose = SC_VCL_FAILURE latches
+varnish v1 -expect sc_vcl_failure == 2
+
+logexpect l1 -wait
+
+#######################################################################
+# Fail in vcl_synth
+
+logexpect l1 -v v1 -g raw {
+	expect * 1007	VCL_call	"SYNTH"
+	expect * 1007	Debug		"Forced failure"
+	expect 0 1007	VCL_return	"fail"
+} -start
+
+client c1 {
+	txreq -hdr "foo: bar"
+	expect_close
+} -run
+
+varnish v1 -expect sc_vcl_failure == 3
+
+logexpect l1 -wait
diff --git a/include/tbl/sess_close.h b/include/tbl/sess_close.h
index 0dcbcbc..c20e71c 100644
--- a/include/tbl/sess_close.h
+++ b/include/tbl/sess_close.h
@@ -46,6 +46,7 @@ SESS_CLOSE(OVERLOAD,	  overload,	1,	"Out of some resource")
 SESS_CLOSE(PIPE_OVERFLOW, pipe_overflow,1,	"Session pipe overflow")
 SESS_CLOSE(RANGE_SHORT,   range_short,	1,	"Insufficient data for range")
 SESS_CLOSE(REQ_HTTP20,	  req_http20,	1,	"HTTP2 not accepted")
+SESS_CLOSE(VCL_FAILURE,	  vcl_failure,	1,	"VCL failure")
 #undef SESS_CLOSE
 
 /*lint -restore */
diff --git a/include/tbl/steps.h b/include/tbl/steps.h
index 10d8f9f..ab8d742 100644
--- a/include/tbl/steps.h
+++ b/include/tbl/steps.h
@@ -40,6 +40,7 @@
   REQ_STEP(miss,		MISS,		(wrk, req))
   REQ_STEP(fetch,		FETCH,		(wrk, req))
   REQ_STEP(deliver,		DELIVER,	(wrk, req))
+  REQ_STEP(vclfail,		VCLFAIL,	(wrk, req))
   REQ_STEP(synth,		SYNTH,		(wrk, req))
   REQ_STEP(transmit,		TRANSMIT,	(wrk, req))
   #undef REQ_STEP
diff --git a/lib/libvcc/generate.py b/lib/libvcc/generate.py
index c71fc1b..ecf4e3f 100755
--- a/lib/libvcc/generate.py
+++ b/lib/libvcc/generate.py
@@ -90,7 +90,7 @@ returns = (
 
 	('recv',
 		"C",
-		('synth', 'pass', 'pipe', 'hash', 'purge', 'vcl')
+		('fail', 'synth', 'pass', 'pipe', 'hash', 'purge', 'vcl')
 	),
 	('pipe',
 		"C",
@@ -122,7 +122,7 @@ returns = (
 	),
 	('synth',
 		"C",
-		('restart', 'deliver',)
+		('fail', 'restart', 'deliver',)
 	),
 
 	###############################################################



More information about the varnish-commit mailing list