[master] cca67b6 Fix a ESI+gzip corner case which had escaped notice until now.
Poul-Henning Kamp
phk at FreeBSD.org
Tue Mar 29 21:58:04 CEST 2016
commit cca67b6dd0480e6fd36304e247ab14b6bfd48f60
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 0dde0b6..ecb01bc 100644
--- a/bin/varnishd/cache/cache_esi_deliver.c
+++ b/bin/varnishd/cache/cache_esi_deliver.c
@@ -232,13 +232,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);
@@ -255,6 +256,13 @@ VDP_ESI(struct req *req, enum vdp_action act, void **priv,
}
pp = ptr;
+ if (req->esi_level > 0) {
+ assert(req->transport == &VED_transport);
+ CAST_OBJ_NOTNULL(pecx, req->transport_priv, ECX_MAGIC);
+ if (!pecx->isgzip)
+ pecx = NULL;
+ }
+
while (1) {
switch (ecx->state) {
case 0:
@@ -265,26 +273,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) {
@@ -307,11 +304,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;
@@ -349,7 +344,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.
@@ -367,10 +362,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;
@@ -469,10 +461,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