[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