test "VCL: test syntax/semantic checks on backend decls."
+# Missing backend
+varnish v1 -badvcl {
+}
+
+# Reference to non-existent backend
+varnish v1 -badvcl {
+ backend b1 {
+ .host = "localhost";
+ }
+ sub vcl_recv {
+ set req.backend = b2;
+ }
+}
+
# Missing .host
varnish v1 -badvcl {
backend b1 {
{ .weight = 1; .backend = 3745; } // Brownie points for getting the joke
}
}
+
+# Check backend reference by name
+varnish v1 -badvcl {
+ backend b1 { .host = "127.0.0.2"; }
+ backend b2 b1;
+}
+
+# Check backend reference by non-C-compat name
+varnish v1 -badvcl {
+ backend b-1 { .host = "127.0.0.2"; }
+}
+
+# Assign backend by non-C-compat name
+# Check backend reference by non-C-compat name
+varnish v1 -badvcl {
+ backend b1 { .host = "127.0.0.2"; }
+ sub vcl_recv {
+ set req.backend = b-1;
+ }
+}
return;
}
vcc_NextToken(tl);
+ vcc_ExpectCid(tl);
+ ERRCHK(tl);
vcc_AddRef(tl, tl->t, R_BACKEND);
Fb(tl, 0, "VGC_backend_%.*s", PF(tl->t));
vcc_NextToken(tl);
* SUCH DAMAGE.
*
* $Id$
+ *
+ * A necessary explanation of a convoluted policy:
+ *
+ * In VCL we have backends and directors.
+ *
+ * In VRT we have directors which reference (a number of) backend hosts.
+ *
+ * A VCL backend therefore has an implicit director of type "simple" created
+ * by the compiler, but not visible in VCL.
+ *
+ * A VCL backend is a "named host", these can be referenced by name form
+ * VCL directors, but not from VCL backends.
+ *
+ * The reason for this quasimadness is that we want to collect statistics
+ * for each actual kickable hardware backend machine, but we want to be
+ * able to refer to them multiple times in different directors.
+ *
+ * At the same time, we do not want to force users to declare each backend
+ * host with a name, if all they want to do is put it into a director, so
+ * backend hosts can be declared inline in the director, in which case
+ * its identity is the director and its numerical index therein.
*/
#include "config.h"
#include "vcc_compile.h"
#include "libvarnish.h"
+struct host {
+ VTAILQ_ENTRY(host) list;
+ int hnum;
+ struct token *name;
+};
+
+
static const char *
CheckHostPort(const char *host, const char *port)
{
vcc_ParseBackend(struct tokenlist *tl)
{
struct host *h;
- int nbh;
h = TlAlloc(tl, sizeof *h);
vcc_NextToken(tl);
- ExpectErr(tl, ID); /* name */
+ vcc_ExpectCid(tl); /* ID: name */
+ ERRCHK(tl);
h->name = tl->t;
vcc_NextToken(tl);
- vcc_ParseHostDef(tl, &nbh, h->name, "backend", 0);
+ vcc_ParseHostDef(tl, &h->hnum, h->name, "backend", 0);
ERRCHK(tl);
- h->hnum = nbh;
VTAILQ_INSERT_TAIL(&tl->hosts, h, list);
/* In the compiled vcl we use these macros to refer to backends */
Fh(tl, 1, "\n#define VGC_backend_%.*s (VCL_conf.director[%d])\n",
- PF(h->name), tl->nbackend);
+ PF(h->name), tl->ndirector);
vcc_AddDef(tl, h->name, R_BACKEND);
Fc(tl, 0, "\nstatic const struct vrt_dir_simple sbe_%.*s = {\n",
PF(h->name));
Fc(tl, 0, "\t.name = \"%.*s\",\n", PF(h->name));
- Fc(tl, 0, "\t.host = &bh_%d,\n", nbh);
+ Fc(tl, 0, "\t.host = &bh_%d,\n", h->hnum);
Fc(tl, 0, "};\n");
- tl->nbackend++;
+ tl->ndirector++;
}
/*--------------------------------------------------------------------
t_first = tl->t;
vcc_NextToken(tl); /* ID: director */
- ExpectErr(tl, ID); /* ID: name */
+ vcc_ExpectCid(tl); /* ID: name */
+ ERRCHK(tl);
t_dir = tl->t;
vcc_NextToken(tl);
vcc_ErrWhere(tl, t_first);
return;
}
- tl->nbackend++;
+ tl->ndirector++;
}
}
Fc(tl, 0, "};\n");
- Fc(tl, 0, "\nstatic struct director\t*directors[%d];\n", tl->nbackend);
+ Fc(tl, 0, "\nstatic struct director\t*directors[%d];\n",
+ tl->ndirector);
Fc(tl, 0, "\nconst struct VCL_conf VCL_conf = {\n");
Fc(tl, 0, "\t.magic = VCL_CONF_MAGIC,\n");
Fc(tl, 0, "\t.init_func = VGC_Init,\n");
Fc(tl, 0, "\t.fini_func = VGC_Fini,\n");
- Fc(tl, 0, "\t.ndirector = %d,\n", tl->nbackend);
+ Fc(tl, 0, "\t.ndirector = %d,\n", tl->ndirector);
Fc(tl, 0, "\t.director = directors,\n");
Fc(tl, 0, "\t.ref = VGC_ref,\n");
Fc(tl, 0, "\t.nref = VGC_NREFS,\n");
return (vcc_DestroyTokenList(tl, NULL));
/* Check if we have any backends at all */
- if (tl->nbackend == 0) {
+ if (tl->ndirector == 0) {
vsb_printf(tl->sb,
- "No backends in VCL program, at least one is necessary.\n");
+ "No backends or directors found in VCL program, "
+ "at least one is necessary.\n");
tl->err = 1;
return (vcc_DestroyTokenList(tl, NULL));
}
char *dec;
};
-struct host {
- VTAILQ_ENTRY(host) list;
- unsigned hnum;
- struct token *name;
-};
-
VTAILQ_HEAD(tokenhead, token);
struct tokenlist {
struct vsb *sb;
int err;
int nbackend_host;
- int nbackend;
+ int ndirector;
VTAILQ_HEAD(, proc) procs;
struct proc *curproc;
struct proc *mprocs[N_METHODS];
void vcc__Expect(struct tokenlist *tl, unsigned tok, int line);
int vcc_Teq(const struct token *t1, const struct token *t2);
int vcc_IdIs(const struct token *t, const char *p);
+int vcc_isCid(struct token *t);
+void vcc_ExpectCid(struct tokenlist *tl);
void vcc_Lexer(struct tokenlist *tl, struct source *sp);
void vcc_NextToken(struct tokenlist *tl);
void vcc__ErrInternal(struct tokenlist *tl, const char *func, unsigned line);
unsigned u;
Fh(tl, 1, "\n#define VGC_backend_%.*s (VCL_conf.director[%d])\n",
- PF(t_dir), tl->nbackend);
+ PF(t_dir), tl->ndirector);
vcc_AddDef(tl, t_dir, R_BACKEND);
fs = vcc_FldSpec(tl, "!backend", "!weight", NULL);
return (1);
}
+/*--------------------------------------------------------------------
+ * Check that we have a C-identifier
+ */
+
+int
+vcc_isCid(struct token *t)
+{
+ const char *q;
+
+ assert(t->tok == ID);
+ for (q = t->b; q < t->e; q++) {
+ if (!isalnum(*q) && *q != '_')
+ return (0);
+ }
+ return (1);
+}
+
+void
+vcc_ExpectCid(struct tokenlist *tl)
+{
+
+ ExpectErr(tl, ID);
+ ERRCHK(tl);
+ if (vcc_isCid(tl->t))
+ return;
+ vsb_printf(tl->sb, "Identifier ");
+ vcc_ErrToken(tl, tl->t);
+ vsb_printf(tl->sb,
+ " contains illegal characters, use [0-9a-zA-Z_] only.\n");
+ vcc_ErrWhere(tl, tl->t);
+}
+
/*--------------------------------------------------------------------
* Decode %xx in a string
*/
r->name = t;
/* The first backend is the default and thus has an implicit ref */
- if (type == R_BACKEND && tl->nbackend == 0)
+ if (type == R_BACKEND && tl->ndirector == 0)
r->refcnt++;
}