[4.1] ed9b6b5 Fix a ESI+gzip corner case which had escaped notice until now.

Federico G. Schwindt fgsch at lodoss.net
Thu Mar 31 17:29:05 CEST 2016


commit ed9b6b5c69800cc92f959a616f50739b0d412723
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Tue Mar 29 19:54:04 2016 +0000

    Fix a ESI+gzip corner case which had escaped notice until now.
    
    When ESI delivering a gzip'ed object, emit the GZIP header+tail
    precisely if no parent ESI has done so.
    
    Fixes:	#1878
    Testcase by:	fgs

diff --git a/bin/varnishd/cache/cache_esi_deliver.c b/bin/varnishd/cache/cache_esi_deliver.c
index 1bfd365..32c8b90 100644
--- a/bin/varnishd/cache/cache_esi_deliver.c
+++ b/bin/varnishd/cache/cache_esi_deliver.c
@@ -228,13 +228,14 @@ VDP_ESI(struct req *req, enum vdp_action act, void **priv,
 	uint32_t icrc = 0;
 	uint8_t tailbuf[8 + 5];
 	const uint8_t *pp;
-	struct ecx *ecx, *pecx;
+	struct ecx *ecx, *pecx = NULL;
 	int retval = 0;
 
 	if (act == VDP_INIT) {
 		AZ(*priv);
 		ALLOC_OBJ(ecx, ECX_MAGIC);
 		AN(ecx);
+		assert(sizeof gzip_hdr == 10);
 		ecx->preq = req;
 		*priv = ecx;
 		RFC2616_Weaken_Etag(req->resp);
@@ -251,6 +252,12 @@ VDP_ESI(struct req *req, enum vdp_action act, void **priv,
 	}
 	pp = ptr;
 
+	if (req->esi_level > 0) {
+		CAST_OBJ_NOTNULL(pecx, req->transport_priv, ECX_MAGIC);
+		if (!pecx->isgzip)
+			pecx = NULL;
+	}
+
 	while (1) {
 		switch (ecx->state) {
 		case 0:
@@ -261,26 +268,15 @@ VDP_ESI(struct req *req, enum vdp_action act, void **priv,
 			ecx->e = ecx->p + l;
 
 			if (*ecx->p == VEC_GZ) {
-				ecx->isgzip = 1;
-				ecx->p++;
-			}
-
-			if (req->esi_level == 0) {
-				/*
-				 * Only the top level document gets to
-				 * decide this.
-				 */
-				if (ecx->isgzip) {
-					assert(sizeof gzip_hdr == 10);
-					/* Send out the gzip header */
+				if (pecx == NULL)
 					retval = VDP_bytes(req, VDP_NULL,
 					    gzip_hdr, 10);
-					ecx->l_crc = 0;
-					ecx->crc = crc32(0L, Z_NULL, 0);
-				}
+				ecx->l_crc = 0;
+				ecx->crc = crc32(0L, Z_NULL, 0);
+				ecx->isgzip = 1;
+				ecx->p++;
 			}
 			ecx->state = 1;
-
 			break;
 		case 1:
 			if (ecx->p >= ecx->e) {
@@ -303,11 +299,9 @@ VDP_ESI(struct req *req, enum vdp_action act, void **priv,
 						return (-1);
 					icrc = vbe32dec(ecx->p);
 					ecx->p += 4;
-					if (ecx->isgzip) {
-						ecx->crc = crc32_combine(
-						    ecx->crc, icrc, l);
-						ecx->l_crc += l;
-					}
+					ecx->crc = crc32_combine(
+					    ecx->crc, icrc, l);
+					ecx->l_crc += l;
 				}
 				ecx->state = 3;
 				break;
@@ -345,7 +339,7 @@ VDP_ESI(struct req *req, enum vdp_action act, void **priv,
 			}
 			break;
 		case 2:
-			if (ecx->isgzip && req->esi_level == 0) {
+			if (ecx->isgzip && pecx == NULL) {
 				/*
 				 * We are bytealigned here, so simply emit
 				 * a gzip literal block with finish bit set.
@@ -363,10 +357,7 @@ VDP_ESI(struct req *req, enum vdp_action act, void **priv,
 				vle32enc(tailbuf + 9, ecx->l_crc);
 
 				(void)VDP_bytes(req, VDP_NULL, tailbuf, 13);
-			}
-			if (req->transport->deliver == VED_Deliver) {
-				CAST_OBJ_NOTNULL(pecx, req->transport_priv,
-				    ECX_MAGIC);
+			} else if (pecx != NULL) {
 				pecx->crc = crc32_combine(pecx->crc,
 				    ecx->crc, ecx->l_crc);
 				pecx->l_crc += ecx->l_crc;
@@ -465,10 +456,9 @@ ved_pretend_gzip(struct req *req, enum vdp_action act, void **priv,
 
 	p = pv;
 
-	if (ecx->isgzip) {
-		ecx->crc = crc32(ecx->crc, p, l);
-		ecx->l_crc += l;
-	}
+	AN (ecx->isgzip);
+	ecx->crc = crc32(ecx->crc, p, l);
+	ecx->l_crc += l;
 
 	lx = 65535;
 	buf1[0] = 0;
diff --git a/bin/varnishtest/tests/r01781.vtc b/bin/varnishtest/tests/r01781.vtc
index 5b796d8..174f82f 100644
--- a/bin/varnishtest/tests/r01781.vtc
+++ b/bin/varnishtest/tests/r01781.vtc
@@ -5,9 +5,11 @@ server s1 {
 	txresp -body {<esi:include src="/1"/>Baz}
 
 	rxreq
+	expect req.url == /1
 	txresp -body {<esi:include src="/2"/>Bar}
 
 	rxreq
+	expect req.url == /2
 	txresp -body {Foo}
 } -start
 
@@ -19,6 +21,10 @@ varnish v1 -vcl+backend {
 } -start
 
 client c1 {
+	txreq
+	rxresp
+	expect resp.body == "FooBarBaz"
+
 	txreq -hdr "Accept-Encoding: gzip"
 	rxresp
 	expect resp.http.content-encoding == "gzip"
diff --git a/bin/varnishtest/tests/r01878.vtc b/bin/varnishtest/tests/r01878.vtc
new file mode 100644
index 0000000..fc75a44
--- /dev/null
+++ b/bin/varnishtest/tests/r01878.vtc
@@ -0,0 +1,32 @@
+varnishtest ""
+
+server s1 {
+	rxreq
+	txresp -hdr "id: /" -body {<1><esi:include src="/foo"/></1>}
+
+	rxreq
+	expect req.url == "/foo"
+	expect req.http.accept-encoding == "gzip"
+	txresp -hdr "id: foo" -gzipbody {<2><esi:include src="/bar"/></2>}
+
+	rxreq
+	expect req.url == "/bar"
+	txresp -hdr "id: bar" -body "<3>bar</3>"
+} -start
+
+varnish v1 -vcl+backend {
+	sub vcl_backend_response {
+		if (bereq.url != "/bar") {
+			set beresp.do_esi = true;
+		}
+		return (deliver);
+	}
+} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.bodylen == 24
+	expect resp.body == {<1><2><3>bar</3></2></1>}
+} -run
+



More information about the varnish-commit mailing list