[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