[master] cb446a38d vcc: set BODY [+]= STRINGS|BLOB

Dridi Boukelmoune dridi.boukelmoune at gmail.com
Tue Dec 7 06:51:06 UTC 2021


commit cb446a38d75c7768b5c5f7b4330f45d69375ba4a
Author: Dridi Boukelmoune <dridi.boukelmoune at gmail.com>
Date:   Mon Nov 29 18:35:57 2021 +0100

    vcc: set BODY [+]= STRINGS|BLOB
    
    This reuses the stringform concept and introduces a similar bodyform
    flag for STRINGS and BLOB types. We can now assign either a STRING or
    a BLOB to [be]resp.body, without breaking the VRT ABI and API. In fact,
    the VRT API now uses a void* C type for the BODY VCL type and finds
    which type to use based on enum lbody_e.
    
    The enum completely changed but macros were added to maintain the API,
    and because of this change, enum lbody_e literals are formatted in two
    steps. As a result the BODY type grew another noindent flag. It prevents
    the insertion of white space between the LBODY_{ADD,SET}_ prefix and the
    type name suffix (BLOB or STRANDS).

diff --git a/bin/varnishd/cache/cache_vrt_var.c b/bin/varnishd/cache/cache_vrt_var.c
index 64b7257d4..d80b96526 100644
--- a/bin/varnishd/cache/cache_vrt_var.c
+++ b/bin/varnishd/cache/cache_vrt_var.c
@@ -965,17 +965,29 @@ VRT_r_resp_do_esi(VRT_CTX)
 #define VRT_BODY_L(which)					\
 VCL_VOID							\
 VRT_l_##which##_body(VRT_CTX, enum lbody_e type,		\
-    const char *str, VCL_STRANDS s)				\
+    const char *str, VCL_BODY body)				\
 {								\
 	int n;							\
 	struct vsb *vsb;					\
+	VCL_STRANDS s;						\
+	VCL_BLOB b;						\
 								\
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);			\
+	AN(body);						\
 	CAST_OBJ_NOTNULL(vsb, ctx->specific, VSB_MAGIC);	\
-	assert(type == LBODY_SET || type == LBODY_ADD);		\
-	if (type == LBODY_SET)					\
+	if (type == LBODY_SET_STRING || type == LBODY_SET_BLOB)	\
 		VSB_clear(vsb);					\
+	if (type == LBODY_SET_BLOB || type == LBODY_ADD_BLOB) {	\
+		AZ(str);					\
+		b = body;					\
+		VSB_bcat(vsb, b->blob, b->len);			\
+		return;						\
+	}							\
 	if (str != NULL)					\
 		VSB_cat(vsb, str);				\
+	assert(type == LBODY_SET_STRING ||			\
+	    type == LBODY_ADD_STRING);				\
+	s = body;						\
 	for (n = 0; s != NULL && n < s->n; n++)			\
 		if (s->p[n] != NULL)				\
 			VSB_cat(vsb, s->p[n]);			\
diff --git a/bin/varnishtest/tests/r03079.vtc b/bin/varnishtest/tests/r03079.vtc
index 3b2f57204..22da633ac 100644
--- a/bin/varnishtest/tests/r03079.vtc
+++ b/bin/varnishtest/tests/r03079.vtc
@@ -26,7 +26,7 @@ client c1 {
 	expect resp.http.x-powered-by == varnishtest1002
 } -run
 
-# set BODY [+]= STRINGS;
+# set BODY [+]= STRINGS|BLOB;
 
 varnish v1 -vcl {
 	import blob;
@@ -50,11 +50,20 @@ varnish v1 -vcl {
 				set resp.body += "world";
 			}
 		}
+		if (req.url ~ "blob") {
+			set resp.body = blob.decode(HEX, encoded="1100");
+			if (req.url ~ "reset") {
+				set resp.body = blob.decode(HEX, encoded="221100");
+			}
+			if (req.url ~ "add") {
+				set resp.body += blob.decode(HEX, encoded="221100");
+			}
+		}
 		return (deliver);
 	}
 }
 
-client c1 {
+client c2 {
 	txreq -url "/synth"
 	rxresp
 	expect resp.body == hello
@@ -74,4 +83,16 @@ client c1 {
 	txreq -url "/string/add"
 	rxresp
 	expect resp.body == helloworld
+
+	txreq -url "/blob"
+	rxresp
+	expect resp.bodylen == 2
+
+	txreq -url "/blob/reset"
+	rxresp
+	expect resp.bodylen == 3
+
+	txreq -url "/blob/add"
+	rxresp
+	expect resp.bodylen == 5
 } -run
diff --git a/doc/sphinx/reference/vmod.rst b/doc/sphinx/reference/vmod.rst
index 84283745f..10460cd7b 100644
--- a/doc/sphinx/reference/vmod.rst
+++ b/doc/sphinx/reference/vmod.rst
@@ -302,6 +302,13 @@ BLOB
 	An opaque type to pass random bits of memory between VMOD
 	functions.
 
+BODY
+	C-type: ``const void *``
+
+	A type only used on the LHS of an assignment that can take
+	either a blob or an expression that can be converted to a
+	string.
+
 BOOL
 	C-type: ``unsigned``
 
diff --git a/include/vrt.h b/include/vrt.h
index a47250255..f7a1d31e1 100644
--- a/include/vrt.h
+++ b/include/vrt.h
@@ -56,6 +56,14 @@
  * Next (2021-03-15)
  *	VRT_Assign_Backend added
  *	VRT_StaticDirector added
+ *	enum lbody_e changed
+ *	- previous enum lbody_e values are defined as macros
+ *	The following functions changed to take `const char *, BODY`:
+ *	- VRT_l_beresp_body()
+ *	- VRT_l_resp_body()
+ *	BODY can either be a BLOB or a STRANDS, but only a STRANDS
+ *	can take a non-NULL const char * prefix. The changes to BODY
+ *	assignments doesn't break the ABI or the API.
  *
  * 14.0 (2021-09-15)
  *	VIN_n_Arg() no directly returns the directory name.
@@ -328,7 +336,7 @@ extern const struct vrt_blob *vrt_null_blob;
 typedef const struct vrt_acl *			VCL_ACL;
 typedef const struct director *			VCL_BACKEND;
 typedef const struct vrt_blob *			VCL_BLOB;
-typedef const char *				VCL_BODY;
+typedef const void *				VCL_BODY;
 typedef unsigned				VCL_BOOL;
 typedef int64_t					VCL_BYTES;
 typedef vtim_dur				VCL_DURATION;
@@ -615,10 +623,15 @@ VCL_STRING VRT_GetHdr(VRT_CTX, VCL_HEADER);
  */
 
 enum lbody_e {
-	LBODY_SET,
-	LBODY_ADD,
+	LBODY_SET_STRING,
+	LBODY_ADD_STRING,
+	LBODY_SET_BLOB,
+	LBODY_ADD_BLOB,
 };
 
+#define LBODY_SET LBODY_SET_STRING
+#define LBODY_ADD LBODY_ADD_STRING
+
 VCL_BYTES VRT_CacheReqBody(VRT_CTX, VCL_BYTES maxsize);
 
 VCL_STRING VRT_ban_string(VRT_CTX, VCL_STRING);
diff --git a/lib/libvcc/generate.py b/lib/libvcc/generate.py
index a2b318ba8..c50194348 100755
--- a/lib/libvcc/generate.py
+++ b/lib/libvcc/generate.py
@@ -219,7 +219,7 @@ class vardef(object):
             if self.typ == "STRING":
                 s += ctyp.c + ", VCL_STRANDS)"
             elif self.typ == "BODY":
-                s += "enum lbody_e, " + ctyp.c + ", VCL_STRANDS)"
+                s += "enum lbody_e, const char *, " + ctyp.c + ")"
             else:
                 s += "VCL_" + self.typ + ")"
             varproto(s)
diff --git a/lib/libvcc/vcc_action.c b/lib/libvcc/vcc_action.c
index 0ed675da6..f7c2ce29f 100644
--- a/lib/libvcc/vcc_action.c
+++ b/lib/libvcc/vcc_action.c
@@ -121,8 +121,8 @@ static const struct assign {
 	{ STRING,	'=',		STRANDS, "0,\n" },
 	{ HEADER,	T_INCR,		STRANDS, "VRT_GetHdr(ctx, \v),\n" },
 	{ HEADER,	'=',		STRANDS, "0,\n" },
-	{ BODY,		'=',		STRANDS, "LBODY_SET, 0,\n" },
-	{ BODY,		T_INCR,		STRANDS, "LBODY_ADD, 0,\n" },
+	{ BODY,		'=',		BODY, "LBODY_SET_" },
+	{ BODY,		T_INCR,		BODY, "LBODY_ADD_" },
 	{ VOID,		'=',		VOID }
 };
 
diff --git a/lib/libvcc/vcc_compile.h b/lib/libvcc/vcc_compile.h
index 6ce150c4c..76b2cab73 100644
--- a/lib/libvcc/vcc_compile.h
+++ b/lib/libvcc/vcc_compile.h
@@ -119,6 +119,8 @@ struct type {
 	const char		*tostring;
 	vcc_type_t		multype;
 	int			stringform;
+	int			bodyform;
+	int			noindent;
 };
 
 #define VCC_TYPE(UC, lc)	extern const struct type UC[1];
diff --git a/lib/libvcc/vcc_expr.c b/lib/libvcc/vcc_expr.c
index bc9864d29..0805f9340 100644
--- a/lib/libvcc/vcc_expr.c
+++ b/lib/libvcc/vcc_expr.c
@@ -237,8 +237,10 @@ vcc_expr_fmt(struct vsb *d, int ind, const struct expr *e1)
 	char *p;
 	int i;
 
-	for (i = 0; i < ind; i++)
-		VSB_cat(d, " ");
+	if (!e1->fmt->noindent) {
+		for (i = 0; i < ind; i++)
+			VSB_putc(d, ' ');
+	}
 	p = VSB_data(e1->vsb);
 	while (*p != '\0') {
 		if (*p == '\n') {
@@ -246,7 +248,7 @@ vcc_expr_fmt(struct vsb *d, int ind, const struct expr *e1)
 			if (*++p == '\0')
 				break;
 			for (i = 0; i < ind; i++)
-				VSB_cat(d, " ");
+				VSB_putc(d, ' ');
 		} else if (*p != '\v') {
 			VSB_putc(d, *p++);
 		} else {
@@ -1417,6 +1419,8 @@ vcc_expr0(struct vcc *tl, struct expr **e, vcc_type_t fmt)
 		vcc_expr_cor(tl, e, fmt);
 	ERRCHK(tl);
 
+	assert((*e)->fmt != BODY);
+
 	if ((*e)->fmt == fmt)
 		return;
 
@@ -1431,6 +1435,18 @@ vcc_expr0(struct vcc *tl, struct expr **e, vcc_type_t fmt)
 		return;
 	}
 
+	if (fmt == BODY && !(*e)->fmt->bodyform)
+		vcc_expr_tostring(tl, e, STRINGS);
+
+	if (fmt == BODY && (*e)->fmt->bodyform) {
+		if ((*e)->fmt == STRINGS)
+			*e = vcc_expr_edit(tl, BODY, "STRING, 0, \vT", *e, NULL);
+		else if ((*e)->fmt == BLOB)
+			*e = vcc_expr_edit(tl, BODY, "BLOB, 0, \v1", *e, NULL);
+		else
+			WRONG("Unhandled bodyform");
+	}
+
 	if ((*e)->fmt == STRINGS && fmt->stringform) {
 		if (fmt == STRING)
 			*e = vcc_expr_edit(tl, STRING, "\vS", *e, NULL);
diff --git a/lib/libvcc/vcc_types.c b/lib/libvcc/vcc_types.c
index 829bb2c2e..cfa6714b3 100644
--- a/lib/libvcc/vcc_types.c
+++ b/lib/libvcc/vcc_types.c
@@ -78,12 +78,14 @@ const struct type BACKEND[1] = {{
 const struct type BLOB[1] = {{
 	.magic =		TYPE_MAGIC,
 	.name =			"BLOB",
+	.bodyform =		1,
 	.tostring =		"VRT_BLOB_string(ctx, \v1)",
 }};
 
 const struct type BODY[1] = {{
 	.magic =		TYPE_MAGIC,
 	.name =			"BODY",
+	.noindent =		1,
 }};
 
 const struct type BOOL[1] = {{
@@ -199,6 +201,7 @@ const struct type STRINGS[1] = {{
 	.magic =		TYPE_MAGIC,
 	.name =			"STRINGS",
 	.methods =		strings_methods,
+	.bodyform =		1,
 	.tostring =		"",
 }};
 


More information about the varnish-commit mailing list