[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