[master] c061b8eb3 Treat multiline VSL queries as if they were OR'ed

Dridi Boukelmoune dridi.boukelmoune at gmail.com
Wed Jun 12 04:58:11 UTC 2019


commit c061b8eb3f70017d343dd680a9886188b22890b9
Author: Dridi Boukelmoune <dridi.boukelmoune at gmail.com>
Date:   Fri May 17 10:06:05 2019 +0200

    Treat multiline VSL queries as if they were OR'ed
    
    The two following queries now become equivalent:
    
        vut -g request -q '
            # catch varnish errors
            *Error
    
            # catch backend errors
            BerespStatus >= 500
        '
    
        vut -g request -q '(*Error) or (BerespStatus >= 500)'
    
    It becomes interesting when we wish to capture transactions for
    different scenarios but would like to decompose them cleanly.
    Especially when the query of an individual scenario is rather
    complex and OR'ing everything manually would become cumbersome.
    
    This diff is better viewed with the --ignore-all-space flag.

diff --git a/bin/varnishtest/tests/u00014.vtc b/bin/varnishtest/tests/u00014.vtc
new file mode 100644
index 000000000..648bc45e6
--- /dev/null
+++ b/bin/varnishtest/tests/u00014.vtc
@@ -0,0 +1,91 @@
+varnishtest "VSL compound queries"
+
+# This test case compares individual query scenarios to their
+# compounded queries counterparts.
+
+server s1 {
+	rxreq
+	txresp -status 500
+
+	rxreq
+	txresp -status 503
+} -start
+
+varnish v1 -vcl+backend "" -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 500
+
+	txreq
+	rxresp
+	expect resp.status == 503
+} -run
+
+# Let's fist create a script to reduce in all the variants below.
+
+shell {
+	cat >ncsa.sh <<-EOF
+	#!/bin/sh
+
+	varnishncsa -d -n ${v1_name} -F '%s' "\$@" |
+	tr '\n' ' '
+	# '
+	EOF
+	chmod +x ncsa.sh
+}
+
+shell -match "^500 503 $" {
+	# no query
+	./ncsa.sh
+}
+
+shell -err -expect "Query expression error" {
+	# empty query
+	varnishncsa -d -n ${v1_name} -q ''
+}
+
+shell -err -expect "Query expression error" {
+	varnishncsa -d -n ${v1_name} -q '
+		# empty multiline query
+	'
+}
+
+shell -err -expect "Query expression error" {
+	varnishncsa -d -n ${v1_name} -q '
+		* ~ "Incomplete quoted string
+	'
+}
+
+shell -match "^500 $" {
+	# single query 1
+	./ncsa.sh -q 'RespStatus == 500'
+}
+
+shell -match "^503 $" {
+	# single query 2
+	./ncsa.sh -q 'RespStatus == 503'
+}
+
+shell -match "^500 503 $" {
+	# query 1 OR query 2
+	./ncsa.sh -q '(RespStatus == 500) or (RespStatus == 503)'
+}
+
+shell -match "^500 503 $" {
+	./ncsa.sh -q '
+		# query 1
+		RespStatus == 500
+
+		# query 2
+		RespStatus == 503
+	'
+}
+
+shell -match "^500 503 $" {
+	./ncsa.sh -q '
+		RespStatus == 500 # query 1
+		RespStatus == 503 # query 2
+	'
+}
diff --git a/doc/sphinx/reference/vsl-query.rst b/doc/sphinx/reference/vsl-query.rst
index 92b97c9e7..67cf2f02d 100644
--- a/doc/sphinx/reference/vsl-query.rst
+++ b/doc/sphinx/reference/vsl-query.rst
@@ -131,6 +131,26 @@ whose id can be obtained from an ``X-Varnish`` HTTP header, the
 default "guru meditation" error page, or ``Begin`` and ``Link`` log
 records.
 
+A query must fit on a single line, but it is possible to pass multiple
+queries at once, one query per line. Empty lines are ignored, and the
+list of queries is treated as if the 'or' operator was used to combine
+them.
+
+For example this list of queries::
+
+  # catch varnish errors
+  *Error
+
+  # catch backend errors
+  BerespStatus >= 500
+
+is identical to this query::
+
+  (*Error) or (BerespStatus >= 500)
+
+Comments can be used and will be ignored, they start with the ``'#'``
+character.
+
 Record selection criteria
 -------------------------
 
diff --git a/lib/libvarnishapi/vxp_parse.c b/lib/libvarnishapi/vxp_parse.c
index e6db240c5..16f65f42f 100644
--- a/lib/libvarnishapi/vxp_parse.c
+++ b/lib/libvarnishapi/vxp_parse.c
@@ -503,15 +503,30 @@ vxp_expr_or(struct vxp *vxp, struct vex **pvex)
 /*
  * SYNTAX:
  *   expr:
- *     expr_or EOI
+ *     expr_or EOI { 'or' expr_or EOI }?
  */
 
 static void
 vxp_expr(struct vxp *vxp, struct vex **pvex)
 {
-	vxp_expr_or(vxp, pvex);
+	struct vex *a = NULL, *or;
+
+	if (*pvex == NULL) {
+		vxp_expr_or(vxp, pvex);
+		ERRCHK(vxp);
+		ExpectErr(vxp, EOI);
+		return;
+	}
+
+	vxp_expr(vxp, &a);
 	ERRCHK(vxp);
-	ExpectErr(vxp, EOI);
+
+	or = vex_alloc(vxp);
+	AN(or);
+	or->tok = T_OR;
+	or->b = *pvex;
+	or->a = a;
+	*pvex = or;
 }
 
 /*
@@ -523,17 +538,27 @@ vxp_Parse(struct vxp *vxp)
 {
 	struct vex *vex = NULL;
 
+	AZ(vxp->err);
 	vxp->t = VTAILQ_FIRST(&vxp->tokens);
-	if (vxp->t == NULL)
-		return (NULL);
 
-	vxp_expr(vxp, &vex);
+	while (vxp->t != NULL) {
+		/* Ignore empty queries */
+		while (vxp->t != NULL && vxp->t->tok == EOI)
+			vxp->t = VTAILQ_NEXT(vxp->t, list);
+
+		if (vxp->t == NULL)
+			break;
+
+		vxp_expr(vxp, &vex);
+
+		if (vxp->err) {
+			if (vex)
+				vex_Free(&vex);
+			AZ(vex);
+			return (NULL);
+		}
 
-	if (vxp->err) {
-		if (vex)
-			vex_Free(&vex);
-		AZ(vex);
-		return (NULL);
+		vxp->t = VTAILQ_NEXT(vxp->t, list);
 	}
 
 	return (vex);


More information about the varnish-commit mailing list