[6.0] ca63271d6 Add VRT functions for STRANDS.

Dridi Boukelmoune dridi.boukelmoune at gmail.com
Wed Jul 3 14:40:10 UTC 2019


commit ca63271d6b862ec33c03c41e64f971eb89c6469a
Author: Geoff Simmons <geoff at uplex.de>
Date:   Thu Jul 19 17:03:30 2018 +0200

    Add VRT functions for STRANDS.
    
    Re-implementations of the current functions for STRING_LIST.
    
    Closes #2733
    
    Conflicts:
            include/vrt.h
            lib/libvmod_debug/vmod.vcc
            lib/libvmod_debug/vmod_debug.c
    
    This introduces VRT 7.1 for the 6.0 releases.

diff --git a/bin/varnishd/cache/cache_vrt.c b/bin/varnishd/cache/cache_vrt.c
index 4ff427f35..28ca3d8fd 100644
--- a/bin/varnishd/cache/cache_vrt.c
+++ b/bin/varnishd/cache/cache_vrt.c
@@ -344,6 +344,117 @@ VRT_CollectString(VRT_CTX, const char *p, ...)
 	return (b);
 }
 
+/*--------------------------------------------------------------------
+ * Collapse STRANDS into the space provided, or return NULL
+ */
+
+char *
+VRT_Strands(char *d, size_t dl, VCL_STRANDS s)
+{
+	char *b;
+	const char *e;
+	unsigned x;
+
+	AN(d);
+	AN(s);
+	b = d;
+	e = b + dl;
+	for (int i = 0; i < s->n && b < e; i++)
+		if (s->p[i] != NULL && *s->p[i] != '\0') {
+			x = strlen(s->p[i]);
+			if (b + x < e)
+				memcpy(b, s->p[i], x);
+			b += x;
+		}
+	if (b >= e)
+		return (NULL);
+	*b++ = '\0';
+	return (b);
+}
+
+/*--------------------------------------------------------------------
+ * Copy and merge STRANDS into a workspace.
+ */
+
+VCL_STRING
+VRT_StrandsWS(struct ws *ws, const char *h, VCL_STRANDS s)
+{
+	char *b;
+	const char *q = NULL, *e;
+	VCL_STRING r;
+	unsigned u, x;
+	int i;
+
+	AN(s);
+	u = WS_Reserve(ws, 0);
+
+	for (i = 0; i < s->n; i++)
+		if (s->p[i] != NULL && *s->p[i] != '\0') {
+			q = s->p[i];
+			break;
+		}
+
+	if (h != NULL && q == NULL && WS_Inside(ws, h, NULL)) {
+		WS_Release(ws, 0);
+		return (h);
+	}
+
+	if (h == NULL) {
+		if (q == NULL) {
+			WS_Release(ws, 0);
+			return ("");
+		}
+		if (WS_Inside(ws, q, NULL)) {
+			for (i++; i < s->n; i++)
+				if (s->p[i] != NULL && *s->p[i] != '\0')
+					break;
+			if (i == s->n) {
+				WS_Release(ws, 0);
+				return (q);
+			}
+		}
+	}
+
+	b = WS_Front(ws);
+	e = b + u;
+
+	if (h != NULL) {
+		x = strlen(h);
+		if (b + x < e)
+			memcpy(b, h, x);
+		b += x;
+		if (b < e)
+			*b = ' ';
+		b++;
+	}
+	r = VRT_Strands(b, e > b ? e - b : 0, s);
+	if (r == NULL || r == e) {
+		WS_MarkOverflow(ws);
+		WS_Release(ws, 0);
+		return (NULL);
+	}
+	b = WS_Front(ws);
+	WS_Release(ws, r - b);
+	return (b);
+}
+
+/*--------------------------------------------------------------------
+ * Copy and merge STRANDS on the current workspace
+ */
+
+VCL_STRING
+VRT_CollectStrands(VRT_CTX, VCL_STRANDS s)
+{
+	const char *b;
+
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
+	b = VRT_StrandsWS(ctx->ws, NULL, s);
+	if (b == NULL)
+		VRT_fail(ctx, "Workspace overflow");
+	return (b);
+}
+
 /*--------------------------------------------------------------------*/
 
 VCL_VOID
diff --git a/bin/varnishtest/tests/v00058.vtc b/bin/varnishtest/tests/v00058.vtc
new file mode 100644
index 000000000..d76e3d397
--- /dev/null
+++ b/bin/varnishtest/tests/v00058.vtc
@@ -0,0 +1,167 @@
+varnishtest "Test VRT STRANDS functions"
+
+varnish v1 -arg "-i foobar" -vcl {
+	import debug;
+	backend b { .host = "${bad_ip}"; }
+
+	sub vcl_init {
+		# tests VRT_Strands()
+		new c = debug.concat(server.identity + server.hostname + now);
+		new e = debug.concat("" + server.identity + "");
+	}
+
+	sub vcl_recv {
+		return (synth(200));
+	}
+
+	sub vcl_synth {
+		set resp.http.C = c.get();
+		set resp.http.E = e.get();
+
+		set req.http.Foo = "foo";
+		set req.http.Bar = "bar";
+		set req.http.Baz = "baz";
+
+		# test VRT_StrandsWS()
+		set resp.http.Concat-1
+			= debug.concatenate(req.http.Foo + req.http.Bar
+						+ req.http.Baz);
+		set resp.http.Concat-2
+			= debug.concatenate("" + req.http.Unset + req.http.Foo
+						+ req.http.Unset + ""
+						+ req.http.Bar + ""
+						+ req.http.Unset + ""
+						+ req.http.Baz + ""
+						+ req.http.Unset);
+		set resp.http.Concat-3
+			= debug.concatenate(req.http.Foo + req.http.Unset + "");
+		set resp.http.Concat-4
+			= debug.concatenate(req.http.Unset + "" + req.http.Foo);
+		set resp.http.Concat-5
+			= debug.concatenate(req.http.Foo + req.http.Unset
+						+ req.http.Bar);
+		set resp.http.Concat-6 = debug.concatenate(req.http.Foo);
+		set resp.http.Concat-7 = debug.concatenate(req.http.Unset);
+
+		# test VRT_StrandsCollect()
+		set resp.http.Collect-1
+			= debug.collect(req.http.Foo + req.http.Bar
+					+ req.http.Baz);
+		set resp.http.Collect-2
+			= debug.collect("" + req.http.Unset + req.http.Foo
+					+ req.http.Unset + "" + req.http.Bar
+					+ "" + req.http.Unset + ""
+					+ req.http.Baz + "" + req.http.Unset);
+		set resp.http.Collect-3
+			= debug.collect(req.http.Foo + req.http.Unset + "");
+		set resp.http.Collect-4
+			= debug.collect(req.http.Unset + "" + req.http.Foo);
+		set resp.http.Collect-5
+			= debug.collect(req.http.Foo + req.http.Unset
+					+ req.http.Bar);
+		set resp.http.Collect-6 = debug.collect(req.http.Foo);
+		set resp.http.Collect-7 = debug.collect(req.http.Unset);
+
+		# test a STRANDS version of VRT_SetHdr()
+		debug.sethdr(resp.http.Hdr-1, req.http.Foo + req.http.Bar
+						+ req.http.Baz);
+		debug.sethdr(resp.http.Hdr-2,
+				"" + req.http.Unset + req.http.Foo
+				+ req.http.Unset + "" + req.http.Bar + ""
+				+ req.http.Unset + "" + req.http.Baz + ""
+				+ req.http.Unset);
+		debug.sethdr(resp.http.Hdr-3,
+				req.http.Foo + req.http.Unset + "");
+		debug.sethdr(resp.http.Hdr-4,
+				req.http.Unset + "" + req.http.Foo);
+		debug.sethdr(resp.http.Hdr-5,
+				req.http.Foo + req.http.Unset + req.http.Bar);
+		debug.sethdr(resp.http.Hdr-6, req.http.Foo);
+		debug.sethdr(resp.http.Hdr-7, req.http.Unset);
+	}
+} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 200
+	expect resp.http.C ~ "^foobar"
+	expect resp.http.E == "foobar"
+	expect resp.http.Concat-1 == "foobarbaz"
+	expect resp.http.Concat-2 == "foobarbaz"
+	expect resp.http.Concat-3 == "foo"
+	expect resp.http.Concat-4 == "foo"
+	expect resp.http.Concat-5 == "foobar"
+	expect resp.http.Concat-6 == "foo"
+	expect resp.http.Concat-7 == ""
+	expect resp.http.Collect-1 == "foobarbaz"
+	expect resp.http.Collect-2 == "foobarbaz"
+	expect resp.http.Collect-3 == "foo"
+	expect resp.http.Collect-4 == "foo"
+	expect resp.http.Collect-5 == "foobar"
+	expect resp.http.Collect-6 == "foo"
+	expect resp.http.Collect-7 == ""
+	expect resp.http.Hdr-1 == "foobarbaz"
+	expect resp.http.Hdr-2 == "foobarbaz"
+	expect resp.http.Hdr-3 == "foo"
+	expect resp.http.Hdr-4 == "foo"
+	expect resp.http.Hdr-5 == "foobar"
+	expect resp.http.Hdr-6 == "foo"
+	expect resp.http.Hdr-7 == ""
+} -run
+
+# out of workspace
+server s1 {
+	rxreq
+	expect req.http.Foo == "foo"
+	expect req.http.Bar == "bar"
+	expect req.http.Baz == "baz"
+	expect req.http.Quux == "quux"
+	expect req.http.Result == <undef>
+	txresp
+} -start
+
+varnish v1 -vcl+backend {
+	import debug;
+	import vtc;
+
+	sub vcl_recv {
+		set req.http.Foo = "foo";
+		set req.http.Bar = "bar";
+		set req.http.Baz = "baz";
+		set req.http.Quux = "quux";
+
+		vtc.workspace_alloc(client, -12);
+
+		if (req.url == "/1") {
+			# VRT_StrandsWS() marks the WS as overflowed,
+			# returns NULL, but does not invoke VCL failure.
+			# Out-of-workspace doesn't happen until delivery.
+			set req.http.Result
+				= debug.concatenate(req.http.Foo + req.http.Bar
+							+ req.http.Baz
+							+ req.http.Quux);
+		}
+		elsif (req.url == "/2") {
+			# VRT_CollectStrands() invokes VCL failure.
+			set req.http.Result
+				= debug.collect(req.http.Foo + req.http.Bar
+						+ req.http.Baz
+						+ req.http.Quux);
+		}
+	}
+}
+
+client c1 {
+	txreq -url "/1"
+	rxresp
+	expect resp.status == 500
+	expect resp.reason == "Internal Server Error"
+} -run
+
+client c1 {
+	txreq -url "/2"
+	rxresp
+	expect resp.status == 503
+	expect resp.reason == "VCL failed"
+} -run
diff --git a/include/vrt.h b/include/vrt.h
index 53c4b773d..f48df152e 100644
--- a/include/vrt.h
+++ b/include/vrt.h
@@ -52,6 +52,11 @@
  * binary/load-time compatible, increment MAJOR version
  *
  *
+ * 7.1 (unreleased)
+ *	VRT_Strands() added
+ *	VRT_StrandsWS() added
+ *	VRT_CollectStrands() added
+ *	VRT_STRANDS_string() removed from vrt.h (never implemented)
  * 7.0 (2018-03-15)
  *	lots of stuff moved from cache.h to cache_varnishd.h
  *	   (ie: from "$Abi vrt" to "$Abi strict")
@@ -100,7 +105,7 @@
 
 #define VRT_MAJOR_VERSION	7U
 
-#define VRT_MINOR_VERSION	0U
+#define VRT_MINOR_VERSION	1U
 
 /***********************************************************************/
 
@@ -458,6 +463,9 @@ VCL_STEVEDORE VRT_stevedore(const char *nm);
 VCL_STRANDS VRT_BundleStrands(int, struct strands *, char const **,
     const char *f, ...);
 int VRT_CompareStrands(VCL_STRANDS a, VCL_STRANDS b);
+char *VRT_Strands(char *, size_t, VCL_STRANDS);
+VCL_STRING VRT_StrandsWS(struct ws *, const char *, VCL_STRANDS);
+VCL_STRING VRT_CollectStrands(VRT_CTX, VCL_STRANDS);
 
 VCL_STRING VRT_BACKEND_string(VCL_BACKEND);
 VCL_STRING VRT_BOOL_string(VCL_BOOL);
@@ -466,7 +474,6 @@ VCL_STRING VRT_INT_string(VRT_CTX, VCL_INT);
 VCL_STRING VRT_IP_string(VRT_CTX, VCL_IP);
 VCL_STRING VRT_REAL_string(VRT_CTX, VCL_REAL);
 VCL_STRING VRT_STEVEDORE_string(VCL_STEVEDORE);
-VCL_STRING VRT_STRANDS_string(VCL_STRANDS);
 VCL_STRING VRT_TIME_string(VRT_CTX, VCL_TIME);
 
 #ifdef va_start	// XXX: hackish
diff --git a/lib/libvmod_debug/vmod.vcc b/lib/libvmod_debug/vmod.vcc
index 969d38265..234be9e06 100644
--- a/lib/libvmod_debug/vmod.vcc
+++ b/lib/libvmod_debug/vmod.vcc
@@ -184,6 +184,29 @@ $Function VOID vsc_destroy()
 
 Remove a vsc
 
+$Object concat(STRANDS)
+
+Create an object that returns the string formed by concatenating the
+given strings.
+
+$Method STRING .get()
+
+Return the string formed from the concatenation in the constructor.
+
+$Function STRING concatenate(STRANDS)
+
+Return the string formed by concatenating the given strings.
+(Uses VRT_StrandsWS().)
+
+$Function STRING collect(STRANDS)
+
+Return the string formed by concatenating the given strings.
+(Uses VRT_CollectStrands().)
+
+$Function VOID sethdr(HEADER, STRANDS)
+
+Set the given header with the concatenation of the given strings.
+
 $Object obj_opt(PRIV_CALL, PRIV_VCL, PRIV_TASK,
 		[STRING s], [BOOL b])
 
diff --git a/lib/libvmod_debug/vmod_debug.c b/lib/libvmod_debug/vmod_debug.c
index 75e310d54..ebc26f38d 100644
--- a/lib/libvmod_debug/vmod_debug.c
+++ b/lib/libvmod_debug/vmod_debug.c
@@ -415,6 +415,113 @@ xyzzy_vsc_destroy(VRT_CTX)
 	AZ(pthread_mutex_unlock(&vsc_mtx));
 }
 
+struct xyzzy_debug_concat {
+	unsigned	magic;
+#define CONCAT_MAGIC 0x6b746493
+	VCL_STRING	s;
+};
+
+VCL_VOID
+xyzzy_concat__init(VRT_CTX, struct xyzzy_debug_concat **concatp,
+		   const char *vcl_name, VCL_STRANDS s)
+{
+	struct xyzzy_debug_concat *concat;
+	size_t sz = 0;
+	char *p;
+
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	AN(concatp);
+	AZ(*concatp);
+	AN(vcl_name);
+
+	ALLOC_OBJ(concat, CONCAT_MAGIC);
+	AN(concat);
+	*concatp = concat;
+
+	for (int i = 0; i < s->n; i++)
+		if (s->p[i] != NULL)
+			sz += strlen(s->p[i]);
+	p = malloc(sz + 1);
+	AN(p);
+	(void)VRT_Strands(p, sz + 1, s);
+	concat->s = p;
+}
+
+VCL_VOID
+xyzzy_concat__fini(struct xyzzy_debug_concat **concatp)
+{
+	struct xyzzy_debug_concat *concat;
+	void *p;
+
+	if (concatp == NULL || *concatp == NULL)
+		return;
+	CHECK_OBJ(*concatp, CONCAT_MAGIC);
+	concat = *concatp;
+	*concatp = NULL;
+	p = TRUST_ME(concat->s);
+	free(p);
+	FREE_OBJ(concat);
+}
+
+VCL_STRING
+xyzzy_concat_get(VRT_CTX, struct xyzzy_debug_concat *concat)
+{
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	CHECK_OBJ_NOTNULL(concat, CONCAT_MAGIC);
+	return (concat->s);
+}
+
+VCL_STRING
+xyzzy_concatenate(VRT_CTX, VCL_STRANDS s)
+{
+	VCL_STRING r;
+
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	r = VRT_StrandsWS(ctx->ws, NULL, s);
+	if (r != NULL && *r != '\0')
+		WS_Assert_Allocated(ctx->ws, r, strlen(r) + 1);
+	return (r);
+}
+
+VCL_STRING
+xyzzy_collect(VRT_CTX, VCL_STRANDS s)
+{
+	VCL_STRING r;
+
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	r = VRT_CollectStrands(ctx, s);
+	if (r != NULL && *r != '\0')
+		WS_Assert_Allocated(ctx->ws, r, strlen(r) + 1);
+	return (r);
+}
+
+/* cf. VRT_SetHdr() */
+VCL_VOID
+xyzzy_sethdr(VRT_CTX, VCL_HEADER hs, VCL_STRANDS s)
+{
+	struct http *hp;
+	const char *b;
+
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	AN(hs);
+	AN(hs->what);
+	hp = VRT_selecthttp(ctx, hs->where);
+	CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
+	if (s->n == 0) {
+		http_Unset(hp, hs->what);
+	} else {
+		b = VRT_StrandsWS(hp->ws, hs->what + 1, s);
+		if (b == NULL) {
+			VSLb(ctx->vsl, SLT_LostHeader, "%s", hs->what + 1);
+		} else {
+			if (*b != '\0')
+				WS_Assert_Allocated(hp->ws, b, strlen(b) + 1);
+			http_Unset(hp, hs->what);
+			http_SetHeader(hp, b);
+		}
+	}
+}
+
 VCL_VOID
 xyzzy_store_ip(VRT_CTX, struct vmod_priv *priv, VCL_IP ip)
 {


More information about the varnish-commit mailing list