[master] 649ad2ba7 add if-range logic

guillaume quintard gquintard at users.noreply.github.com
Mon Nov 11 17:22:06 UTC 2019


commit 649ad2ba79f44fb0213331e8692361d1f6aa0daa
Author: Guillaume Quintard <guillaume at varnish-software.com>
Date:   Sat Nov 2 18:06:16 2019 -0700

    add if-range logic

diff --git a/bin/varnishd/cache/cache_range.c b/bin/varnishd/cache/cache_range.c
index ab96954fd..dcbfeef49 100644
--- a/bin/varnishd/cache/cache_range.c
+++ b/bin/varnishd/cache/cache_range.c
@@ -33,6 +33,7 @@
 #include "cache_filter.h"
 
 #include "vct.h"
+#include <vtim.h>
 
 /*--------------------------------------------------------------------*/
 
@@ -180,6 +181,58 @@ vrg_dorange(struct req *req, const char *r, void **priv)
 	return (NULL);
 }
 
+/*
+ * return 1 if range should be observed, based on if-range value
+ * if-range can either be a date or an ETag [RFC7233 3.2 p8]
+ */
+static int
+vrg_ifrange(struct req *req)
+{
+	const char *p, *e;
+	vtim_real ims, lm, d;
+
+	if (!http_GetHdr(req->http, H_If_Range, &p))	// rfc7233,l,455,456
+		return (1);
+
+	/* strong validation needed */
+	if (p[0] == 'W' && p[1] == '/')			// rfc7233,l,500,501
+		return (0);
+
+	/* ETag */
+	if (p[0] == '"') {				// rfc7233,l,512,514
+		if (!http_GetHdr(req->resp, H_ETag, &e))
+			return (0);
+		if ((e[0] == 'W' && e[1] == '/'))	// rfc7232,l,547,548
+			return (0);
+		return (strcmp(p, e) == 0);		// rfc7232,l,548,548
+	}
+
+	/* assume date, strong check [RFC7232 2.2.2 p7] */
+	if (!(ims = VTIM_parse(p)))			// rfc7233,l,502,512
+		return (0);
+
+	/* the response needs a Date */
+	// rfc7232 fc7232,l,439,440
+	if (!http_GetHdr(req->resp, H_Date, &p) || !(d = VTIM_parse(p)))
+		return (0);
+
+	/* grab the Last Modified value */
+	if (!http_GetHdr(req->resp, H_Last_Modified, &p))
+		return (0);
+
+	lm = VTIM_parse(p);
+	if (!lm)
+		return (0);
+	
+	/* Last Modified must be 60 seconds older than Date */
+	if (lm > d + 60)				// rfc7232,l,442,443
+		return (0);
+
+	if (lm != ims)					// rfc7233,l,455,456
+		return (0);
+	return (1);
+}
+
 static int v_matchproto_(vdp_init_f)
 vrg_range_init(struct req *req, void **priv)
 {
@@ -187,6 +240,8 @@ vrg_range_init(struct req *req, void **priv)
 	const char *err;
 
 	assert(http_GetHdr(req->http, H_Range, &r));
+	if (!vrg_ifrange(req))	// rfc7233,l,455,456
+		return (1);
 	err = vrg_dorange(req, r, priv);
 	if (err == NULL)
 		return (*priv == NULL ? 1 : 0);
diff --git a/bin/varnishtest/tests/c00100.vtc b/bin/varnishtest/tests/c00100.vtc
new file mode 100644
index 000000000..ebf690430
--- /dev/null
+++ b/bin/varnishtest/tests/c00100.vtc
@@ -0,0 +1,88 @@
+varnishtest "if-range header"
+
+server s1 {
+	rxreq
+	txresp -hdr {etag: "foo"} -hdr "last-modified: Wed, 21 Oct 2015 07:28:00 GMT" -bodylen 16
+
+	rxreq
+	txresp -bodylen 16
+} -start
+
+varnish v1 -vcl+backend {} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 200
+	expect resp.bodylen == 16
+
+	# if-range, but no range
+	txreq -hdr {if-range: "foo"}
+	rxresp
+	expect resp.status == 200
+	expect resp.bodylen == 16
+
+	# non-matching etag if-range
+	txreq -hdr {if-range: "fooled"} -hdr "range: bytes=5-9"
+	rxresp
+	expect resp.status == 200
+	expect resp.bodylen == 16
+
+	# matching etag if-range
+	txreq -hdr {if-range: "foo"} -hdr "range: bytes=5-9"
+	rxresp
+	expect resp.status == 206
+	expect resp.bodylen == 5
+
+	# non-matching date if-range (past)
+	txreq -hdr "if-range: Wed, 21 Oct 2015 07:18:00 GMT" -hdr "range: bytes=5-9"
+	rxresp
+	expect resp.status == 200
+	expect resp.bodylen == 16
+
+	# non-matching date if-range (future)
+	txreq -hdr "if-range: Wed, 21 Oct 2015 07:38:00 GMT" -hdr "range: bytes=5-9"
+	rxresp
+	expect resp.status == 200
+	expect resp.bodylen == 16
+
+	# matching etag if-range
+	txreq -hdr "if-range: Wed, 21 Oct 2015 07:28:00 GMT" -hdr "range: bytes=5-9"
+	rxresp
+	expect resp.status == 206
+	expect resp.bodylen == 5
+}-run
+
+varnish v1 -cliok "ban obj.status != x"
+
+# no etag/LM header
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 200
+	expect resp.bodylen == 16
+
+	# non-matching etag if-range
+	txreq -hdr {if-range: "fooled"} -hdr "range: bytes=5-9"
+	rxresp
+	expect resp.status == 200
+	expect resp.bodylen == 16
+
+	# matching etag if-range
+	txreq -hdr {if-range: "foo"} -hdr "range: bytes=5-9"
+	rxresp
+	expect resp.status == 200
+	expect resp.bodylen == 16
+
+	# non-matching date if-range (past)
+	txreq -hdr "if-range: Wed, 21 Oct 2015 07:18:00 GMT" -hdr "range: bytes=5-9"
+	rxresp
+	expect resp.status == 200
+	expect resp.bodylen == 16
+
+	# non-matching date if-range (future)
+	txreq -hdr "if-range: Wed, 21 Oct 2015 07:38:00 GMT" -hdr "range: bytes=5-9"
+	rxresp
+	expect resp.status == 200
+	expect resp.bodylen == 16
+} -run


More information about the varnish-commit mailing list