[master] 5384df7 Don't test gunzip for partial responses
Dridi Boukelmoune
dridi.boukelmoune at gmail.com
Fri Feb 23 15:18:09 UTC 2018
commit 5384df74abd77a54d03727e847e8610c7af068a8
Author: Dridi Boukelmoune <dridi.boukelmoune at gmail.com>
Date: Tue Jan 9 13:29:17 2018 +0100
Don't test gunzip for partial responses
Some user agents like Safari may "probe" specific resources like medias
before getting the full resources usually asking for the first 2 or 11
bytes, probably to peek at magic numbers to figure early whether a
potentially large resource may not be supported (read: video).
If the user agent also advertises gzip support, and the transaction is
known beforehand to not be cacheable, varnishd will forward the Range
header to the backend:
Accept-Encoding: gzip (when http_gzip_support is on)
Range: bytes=0-1
If the response happens to be both encoded and partial, the gunzip test
cannot be performed. Otherwise we systematically end up with a broken
transaction closed prematuraly:
FetchError b tGunzip failed
Gzip b u F - 2 0 0 0 0
Refs #2530
Refs #2554
diff --git a/bin/varnishd/cache/cache_fetch.c b/bin/varnishd/cache/cache_fetch.c
index c31d88f..9faf4ee 100644
--- a/bin/varnishd/cache/cache_fetch.c
+++ b/bin/varnishd/cache/cache_fetch.c
@@ -501,6 +501,8 @@ vbf_stp_fetchbody(struct worker *wrk, struct busyobj *bo)
static int
vbf_figure_out_vfp(struct busyobj *bo)
{
+ unsigned is_partial;
+
/*
* The VCL variables beresp.do_g[un]zip tells us how we want the
* object processed before it is stored.
@@ -514,7 +516,7 @@ vbf_figure_out_vfp(struct busyobj *bo)
*
*/
- /* No body or no GZIP supprt -> done */
+ /* No body or no GZIP support -> done */
if (bo->htc->body_status == BS_NONE ||
bo->htc->content_length == 0 ||
!cache_param->http_gzip_support) {
@@ -524,6 +526,7 @@ vbf_figure_out_vfp(struct busyobj *bo)
return (0);
}
+ is_partial = http_GetStatus(bo->beresp) == 206;
bo->is_gzip = http_HdrIs(bo->beresp, H_Content_Encoding, "gzip");
bo->is_gunzip = !http_GetHdr(bo->beresp, H_Content_Encoding, NULL);
assert(bo->is_gzip == 0 || bo->is_gunzip == 0);
@@ -552,7 +555,7 @@ vbf_figure_out_vfp(struct busyobj *bo)
if (bo->do_gzip)
return (VFP_Push(bo->vfc, &VFP_gzip) == NULL ? -1 : 0);
- if (bo->is_gzip && !bo->do_gunzip)
+ if (bo->is_gzip && !bo->do_gunzip && !is_partial)
return (VFP_Push(bo->vfc, &VFP_testgunzip) == NULL ? -1 : 0);
return (0);
diff --git a/bin/varnishtest/tests/r02530.vtc b/bin/varnishtest/tests/r02530.vtc
new file mode 100644
index 0000000..27b24b2
--- /dev/null
+++ b/bin/varnishtest/tests/r02530.vtc
@@ -0,0 +1,74 @@
+varnishtest "Don't test gunzip for partial responses"
+
+# The use of ETags is only here to ensure they aren't accidentally weakened.
+
+server s1 {
+ # pass'ed range request
+ rxreq
+ expect req.url == "/pass"
+ expect req.http.Accept-Encoding == gzip
+ expect req.http.Range == bytes=0-1
+ txresp -status 206 -nolen \
+ -hdr {ETag: "abc123"} \
+ -hdr "Accept-Ranges: bytes" \
+ -hdr "Content-Encoding: gzip" \
+ -hdr "Content-Length: 2" \
+ -hdr "Content-Range: bytes 0-1/*"
+ sendhex 1f8b
+
+ # unattended partial response
+ rxreq
+ expect req.url == "/miss"
+ expect req.http.Accept-Encoding == gzip
+ expect req.http.Range == <undef>
+ txresp -status 206 -nolen \
+ -hdr {ETag: "123abc"} \
+ -hdr "Accept-Ranges: bytes" \
+ -hdr "Content-Encoding: gzip" \
+ -hdr "Content-Length: 2" \
+ -hdr "Content-Range: bytes 0-1/*"
+ sendhex 1f8b
+} -start
+
+varnish v1 -vcl+backend {
+ sub vcl_recv {
+ if (req.url == "/pass") {
+ return (pass);
+ }
+ }
+} -start
+
+client c1 {
+ txreq -url "/pass" -hdr "Accept-Encoding: gzip" -hdr "Range: bytes=0-1"
+ rxresp
+ expect resp.status == 206
+ expect resp.http.Etag == {"abc123"}
+ expect resp.http.Accept-Ranges == bytes
+ expect resp.http.Content-Range ~ "^bytes 0-1/"
+ expect resp.http.Content-Length == 2
+ expect resp.bodylen == 2
+} -run
+
+varnish v1 -expect n_gzip == 0
+varnish v1 -expect n_gunzip == 0
+varnish v1 -expect n_test_gunzip == 0
+varnish v1 -expect SMA.s0.c_req == 0
+varnish v1 -expect SMA.Transient.c_req == 2
+
+# Invalid partial response, also in Transient
+client c1 {
+ txreq -url "/miss" -hdr "Accept-Encoding: gzip" -hdr "Range: bytes=0-1"
+ rxresp
+ expect resp.status == 206
+ expect resp.http.Etag == {"123abc"}
+ expect resp.http.Accept-Ranges == bytes
+ expect resp.http.Content-Range ~ "^bytes 0-1/"
+ expect resp.http.Content-Length == 2
+ expect resp.bodylen == 2
+} -run
+
+varnish v1 -expect n_gzip == 0
+varnish v1 -expect n_gunzip == 0
+varnish v1 -expect n_test_gunzip == 0
+varnish v1 -expect SMA.s0.c_req == 0
+varnish v1 -expect SMA.Transient.c_req == 4
More information about the varnish-commit
mailing list