[master] 2f0c9c3 Add yet a VTLA: "VDP" Delivery processors

Poul-Henning Kamp phk at varnish-cache.org
Fri Sep 6 09:00:39 CEST 2013


commit 2f0c9c3ce4b17ed0b50c8a79065c6cbe95430e99
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Thu Sep 5 15:44:45 2013 +0000

    Add yet a VTLA: "VDP" Delivery processors
    
    These are stackable, and does stuff on the way out.
    
    The bottom one points to HTTP/1 ie. WRW for now.
    
    On top of that we can push Range: processing.
    
    Modularizing this, makes it trivial to enable Range: support for
    delivery-side gunzip.
    
    (Committed above the Elbe)

diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index f178691..7115141 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -120,6 +120,7 @@ struct object;
 struct objhead;
 struct pool;
 struct poolparam;
+struct req;
 struct sess;
 struct sesspool;
 struct vbc;
@@ -275,6 +276,10 @@ extern struct vfp vfp_gzip;
 extern struct vfp vfp_testgzip;
 extern struct vfp vfp_esi;
 
+/* Deliver processors ------------------------------------------------*/
+
+typedef int vdp_bytes(struct req *, int flush, void *ptr, ssize_t len);
+
 /*--------------------------------------------------------------------*/
 
 struct exp {
@@ -690,6 +695,15 @@ struct req {
 #define RES_ESI_CHILD		(1<<5)
 #define RES_GUNZIP		(1<<6)
 
+	/* Deliver pipeline */
+	vdp_bytes		*vdps[5];
+	int			vdp_nxt;
+
+	/* Range */
+	ssize_t			range_low;
+	ssize_t			range_high;
+	ssize_t			range_off;
+
 	/* Transaction VSL buffer */
 	struct vsl_log		vsl[1];
 
@@ -818,6 +832,18 @@ int HTTP1_IterateReqBody(struct req *req, req_body_iter_f *func, void *priv);
 /* cache_http1_deliver.c */
 void V1D_Deliver(struct req *);
 
+static inline int
+VDP(struct req *req, int flush, void *ptr, ssize_t len)
+{
+	int i, retval;
+
+	/* Call the present layer, while pointing to the next layer down */
+	i = req->vdp_nxt--;
+	retval = req->vdps[i](req, flush, ptr, len);
+	req->vdp_nxt++;
+	return (retval);
+}
+
 /* cache_req_fsm.c [CNT] */
 enum req_fsm_nxt CNT_Request(struct worker *, struct req *);
 
diff --git a/bin/varnishd/cache/cache_gzip.c b/bin/varnishd/cache/cache_gzip.c
index be633d3..a5b2cbd 100644
--- a/bin/varnishd/cache/cache_gzip.c
+++ b/bin/varnishd/cache/cache_gzip.c
@@ -342,9 +342,7 @@ VGZ_WrwGunzip(struct req *req, struct vgz *vg, const void *ibuf,
 		if (vr < VGZ_OK)
 			return (vr);
 		if (vg->m_len == vg->m_sz || vr == VGZ_STUCK) {
-			req->acct_req.bodybytes += vg->m_len;
-			(void)WRW_Write(wrk, vg->m_buf, vg->m_len);
-			(void)WRW_Flush(wrk);
+			(void)VDP(req, 1, vg->m_buf, vg->m_len);
 			vg->m_len = 0;
 			VGZ_Obuf(vg, vg->m_buf, vg->m_sz);
 		}
@@ -369,9 +367,7 @@ VGZ_WrwFlush(struct req *req, struct vgz *vg)
 	if (vg->m_len ==  0)
 		return;
 
-	req->acct_req.bodybytes += vg->m_len;
-	(void)WRW_Write(wrk, vg->m_buf, vg->m_len);
-	(void)WRW_Flush(wrk);
+	(void)VDP(req, 1, vg->m_buf, vg->m_len);
 	vg->m_len = 0;
 	VGZ_Obuf(vg, vg->m_buf, vg->m_sz);
 }
diff --git a/bin/varnishd/cache/cache_http1_deliver.c b/bin/varnishd/cache/cache_http1_deliver.c
index 0b47331..6abae76 100644
--- a/bin/varnishd/cache/cache_http1_deliver.c
+++ b/bin/varnishd/cache/cache_http1_deliver.c
@@ -35,8 +35,57 @@
 
 /*--------------------------------------------------------------------*/
 
+static int __match_proto__(vdp_bytes)
+v1d_bytes(struct req *req, int flush, void *ptr, ssize_t len)
+{
+	ssize_t wl = 0;
+
+	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
+
+	assert(req->vdp_nxt == -1);	/* always at the bottom of the pile */
+
+	if (len > 0)
+		wl = WRW_Write(req->wrk, ptr, len);
+	if (wl > 0)
+		req->acct_req.bodybytes += wl;
+	if (flush && WRW_Flush(req->wrk))
+		return (-1);
+	if (len != wl)
+		return (-1);
+	return (0);
+}
+
+/*--------------------------------------------------------------------*/
+
+static int __match_proto__(vdp_bytes)
+v1d_range_bytes(struct req *req, int flush, void *ptr, ssize_t len)
+{
+	int retval = 0;
+	ssize_t l;
+	char *p = ptr;
+
+	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
+	l = req->range_low - req->range_off;
+	if (l > 0) {
+		if (l > len)
+			l = len;
+		req->range_off += l;
+		p += l;
+		len -= l;
+	}
+	l = req->range_high - req->range_off;
+	if (l > len)
+		l = len;
+	if (flush || l > 0)
+		retval = VDP(req, flush, p, l);
+	req->range_off += len;
+	return (retval);
+}
+
+/*--------------------------------------------------------------------*/
+
 static void
-v1d_dorange(const struct req *req, const char *r, ssize_t *plow, ssize_t *phigh)
+v1d_dorange(struct req *req, const char *r)
 {
 	ssize_t low, high, has_low;
 
@@ -90,13 +139,15 @@ v1d_dorange(const struct req *req, const char *r, ssize_t *plow, ssize_t *phigh)
 	http_PrintfHeader(req->resp, "Content-Range: bytes %jd-%jd/%jd",
 	    (intmax_t)low, (intmax_t)high, (intmax_t)req->obj->len);
 	http_Unset(req->resp, H_Content_Length);
-	assert(req->res_mode & RES_LEN);
-	http_PrintfHeader(req->resp, "Content-Length: %jd",
-	    (intmax_t)(1 + high - low));
+	if (req->res_mode & RES_LEN)
+		http_PrintfHeader(req->resp, "Content-Length: %jd",
+		    (intmax_t)(1 + high - low));
 	http_SetResp(req->resp, "HTTP/1.1", 206, "Partial Content");
 
-	*plow = low;
-	*phigh = high;
+	req->range_off = 0;
+	req->range_low = low;
+	req->range_high = high + 1;
+	req->vdps[++req->vdp_nxt] = v1d_range_bytes;
 }
 
 /*--------------------------------------------------------------------
@@ -140,10 +191,9 @@ v1d_WriteGunzipObj(struct req *req)
 /*--------------------------------------------------------------------*/
 
 static void
-v1d_WriteDirObj(struct req *req, ssize_t low, ssize_t high)
+v1d_WriteDirObj(struct req *req)
 {
-	ssize_t u = 0;
-	ssize_t idx, skip, len;
+	ssize_t len;
 	struct objiter *oi;
 	void *ptr;
 
@@ -152,31 +202,10 @@ v1d_WriteDirObj(struct req *req, ssize_t low, ssize_t high)
 	oi = ObjIterBegin(req->obj);
 	XXXAN(oi);
 
-	idx = 0;
 	while (ObjIter(oi, &ptr, &len)) {
-		u += len;
-		skip = 0;
-		if (idx + len <= low) {
-			/* This segment is too early */
-			idx += len;
-			continue;
-		}
-		if (idx < low) {
-			/* Chop front of segment off */
-			skip += (low - idx);
-			len -= (low - idx);
-			idx += (low - idx);
-		}
-		if (idx + len > high)
-			/* Chop tail of segment off */
-			len = 1 + high - idx;
-
-		idx += len;
-
-		req->acct_req.bodybytes += len;
-		(void)WRW_Write(req->wrk, (char*)ptr + skip, len);
+		if (VDP(req, 0,  ptr, len))
+			break;
 	}
-	assert(u == req->obj->len);
 	ObjIterEnd(&oi);
 }
 
@@ -184,7 +213,6 @@ void
 V1D_Deliver(struct req *req)
 {
 	char *r;
-	ssize_t low, high;
 
 	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
 	CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC);
@@ -263,17 +291,19 @@ V1D_Deliver(struct req *req)
 	/*
 	 * If nothing special planned, we can attempt Range support
 	 */
-	low = 0;
-	high = req->obj->len - 1;
+	req->range_low = 0;
+	req->range_high = req->obj->len - 1;
+
+	req->vdps[0] = v1d_bytes;
+	req->vdp_nxt = 0;
 
 	if (
 	    req->wantbody &&
-	    (req->res_mode & RES_LEN) &&
-	    !(req->res_mode & (RES_ESI|RES_ESI_CHILD|RES_GUNZIP)) &&
+	    !(req->res_mode & (RES_ESI|RES_ESI_CHILD)) &&
 	    cache_param->http_range_support &&
 	    req->obj->response == 200 &&
 	    http_GetHdr(req->http, H_Range, &r))
-		v1d_dorange(req, r, &low, &high);
+		v1d_dorange(req, r);
 
 	WRW_Reserve(req->wrk, &req->sp->fd, req->vsl, req->t_resp);
 
@@ -303,7 +333,7 @@ V1D_Deliver(struct req *req)
 	} else if (req->res_mode & RES_GUNZIP) {
 		v1d_WriteGunzipObj(req);
 	} else {
-		v1d_WriteDirObj(req, low, high);
+		v1d_WriteDirObj(req);
 	}
 
 	if (req->res_mode & RES_CHUNKED && !(req->res_mode & RES_ESI_CHILD))
diff --git a/bin/varnishtest/tests/g00005.vtc b/bin/varnishtest/tests/g00005.vtc
new file mode 100644
index 0000000..9917937
--- /dev/null
+++ b/bin/varnishtest/tests/g00005.vtc
@@ -0,0 +1,30 @@
+varnishtest "test gunzip for client + Range"
+
+server s1 {
+	rxreq
+	expect req.http.accept-encoding == "gzip"
+	txresp -gzipbody FOOBARBARF
+} -start
+
+varnish v1 -cliok "param.set http_gzip_support true" -vcl+backend {
+} -start
+
+client c1 {
+	txreq 
+	rxresp
+	expect resp.bodylen == "10"
+	expect resp.http.content-encoding == <undef>
+
+	txreq -hdr "Accept-encoding: gzip;q=0.1"
+	rxresp
+	expect resp.http.content-encoding == "gzip"
+	gunzip
+	expect resp.bodylen == "10"
+
+	txreq -hdr "Range: bytes=3-5"
+	rxresp
+	expect resp.http.content-encoding == "<undef>"
+	expect resp.bodylen == "3"
+	expect resp.body == "BAR"
+
+} -run



More information about the varnish-commit mailing list