[master] 2b3c76a84 resp.do_esi is undefined after setting resp.filters

Nils Goroll nils.goroll at uplex.de
Sun Apr 5 14:16:08 UTC 2020


commit 2b3c76a843207324bb2f3a3ece5e3d36881dfc52
Author: Nils Goroll <nils.goroll at uplex.de>
Date:   Sun Apr 5 14:48:28 2020 +0200

    resp.do_esi is undefined after setting resp.filters
    
    After fixing resp.filters, resp.do_esi loses its meaning.
    
    Note:
    
    Setting resp.filters also fixes whether or not the gunzip and range VDPs
    are being pushed.
    
    These do not depend on switches, but on request headers. So we need to
    consider the case that a VCL author
    
            - fixes resp.filters
            - and then adds or removes relevant headers
    
    * req.http.Accept-Encoding for the gunzip vdp
    
      if removed: gunzip stays in the VDP list, which is always ok
    
      if added: that is probably wrong anyway and the VCL author can
      be held responsible for their actions as per the warning in the
      resp.filters documentation.
    
    * req.http.Range for the range vdp
    
      if removed: the range vdp vetoes itself in the _init callback
    
      if added: no range handling will be present, which is always ok
      (and see above for VCL author responsibilities)
    
    Fixes #3002

diff --git a/bin/varnishd/cache/cache_vrt_var.c b/bin/varnishd/cache/cache_vrt_var.c
index a911a3622..8782df08d 100644
--- a/bin/varnishd/cache/cache_vrt_var.c
+++ b/bin/varnishd/cache/cache_vrt_var.c
@@ -869,6 +869,15 @@ VRT_r_resp_is_streaming(VRT_CTX)
 
 /*--------------------------------------------------------------------*/
 
+static inline int
+resp_filter_fixed(VRT_CTX, const char *s)
+{
+	if (ctx->req->filter_list == NULL)
+		return (0);
+	VRT_fail(ctx, "resp.filters are already fixed, %s is undefined", s);
+	return (1);
+}
+
 VCL_VOID
 VRT_l_resp_do_esi(VRT_CTX, VCL_BOOL process_esi)
 {
@@ -876,6 +885,8 @@ VRT_l_resp_do_esi(VRT_CTX, VCL_BOOL process_esi)
 	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
 	CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
 	assert(ctx->syntax >= 41);
+	if (resp_filter_fixed(ctx, "resp.do_esi"))
+		return;
 	ctx->req->disable_esi = !process_esi;
 }
 
@@ -886,6 +897,8 @@ VRT_r_resp_do_esi(VRT_CTX)
 	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
 	CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
 	assert(ctx->syntax >= 41);
+	if (resp_filter_fixed(ctx, "resp.do_esi"))
+		return (0);
 	return (!ctx->req->disable_esi);
 }
 
diff --git a/bin/varnishtest/tests/e00015.vtc b/bin/varnishtest/tests/e00015.vtc
index 4df48cec0..951785115 100644
--- a/bin/varnishtest/tests/e00015.vtc
+++ b/bin/varnishtest/tests/e00015.vtc
@@ -71,10 +71,15 @@ server s1 {
 varnish v1 -syntax 4.1 -vcl+backend {
 	sub vcl_deliver {
 		set resp.http.was = resp.do_esi;
+		set resp.http.filter0 = resp.filters;
 		if (req.url == "/top2") {
 			set resp.do_esi = false;
 		}
 		set resp.http.filters = resp.filters;
+		if (req.http.fiddle) {
+			set resp.filters = resp.filters;
+			set resp.do_esi = false;
+		}
 	}
 	sub vcl_backend_response {
 		set beresp.do_esi = true;
@@ -89,6 +94,7 @@ client c1 {
 	expect resp.bodylen == 73
 	expect resp.status == 200
 	expect resp.http.was == true
+	expect resp.http.filter0 == "esi gunzip"
 	expect resp.http.filters == "gunzip"
 
 	txreq -url "/esi"
@@ -96,6 +102,7 @@ client c1 {
 	expect resp.bodylen == 76
 	expect resp.status == 200
 	expect resp.http.was == true
+	expect resp.http.filter0 == "esi"
 	expect resp.http.filters == "esi"
 
 	# see Note on Range above
@@ -120,6 +127,10 @@ client c1 {
 	expect resp.status == 200
 	expect resp.http.was == true
 	expect resp.http.filters == "esi gunzip range"
+
+	txreq -url /top2 -hdr "fiddle: do_esi"
+	rxresp
+	expect resp.status == 503
 } -run
 
 varnish v1 -expect esi_errors == 0
diff --git a/doc/sphinx/reference/vcl_var.rst b/doc/sphinx/reference/vcl_var.rst
index a26c6d7ff..93d0414b8 100644
--- a/doc/sphinx/reference/vcl_var.rst
+++ b/doc/sphinx/reference/vcl_var.rst
@@ -1218,6 +1218,8 @@ resp.http.*
 
 	The HTTP headers that will be returned.
 
+.. XXX does vcl_synth make any sense?
+
 resp.do_esi	``VCL >= 4.1``
 
 	Type: BOOL
@@ -1226,12 +1228,14 @@ resp.do_esi	``VCL >= 4.1``
 
 	Writable from: vcl_deliver, vcl_synth
 
-	Default: Set if ESI parsing has happened.
+	Default: obj.can_esi
 
 	This can be used to selectively disable ESI processing,
 	even though ESI parsing happened during fetch.
 	This is useful when Varnish caches peer with each other.
 
+	It is a VCL error to use resp.do_esi after setting resp.filters.
+
 
 resp.is_streaming
 
@@ -1252,6 +1256,15 @@ resp.filters
 
 	List of VDP filters the resp.body will be pushed through.
 
+	Before resp.filters is set, the value read will be the default
+	filter list as determined by varnish based on resp.do_esi and
+	request headers.
+
+	After resp.filters is set, changing any of the conditions
+	which otherwise determine the filter selection will have no
+	effiect. Using resp.do_esi is an error once resp.filters is
+	set.
+
 Special variables
 ~~~~~~~~~~~~~~~~~
 


More information about the varnish-commit mailing list