From 18f8dcdbb5672cbfef97bf2d0198f034d877981f Mon Sep 17 00:00:00 2001 From: Dridi Boukelmoune Date: Wed, 18 Sep 2024 18:46:16 +0200 Subject: [PATCH] vcc: Internal type for the reserved 'default' symbol A new DEFAULT type identifies symbols called 'default' and types that can have a default symbol carry a pseudo symbol. This approach can reconcile the overloaded default symbols that all share the generic type DEFAULT but carry their respective kinds. This helps remove some of the special casing for default probes and backends whilst offering a sentinel DEFAULT type to safely deal with the special casing where it is actually needed, simplifying the code a wee bit in those areas. Fixes #4177 --- bin/varnishtest/tests/c00042.vtc | 6 +++ lib/libvcc/vcc_backend.c | 69 +++++++++++++++----------------- lib/libvcc/vcc_compile.h | 5 ++- lib/libvcc/vcc_expr.c | 11 +++-- lib/libvcc/vcc_symb.c | 7 +++- lib/libvcc/vcc_types.c | 27 +++++++++++++ 6 files changed, 81 insertions(+), 44 deletions(-) diff --git a/bin/varnishtest/tests/c00042.vtc b/bin/varnishtest/tests/c00042.vtc index a57ec779770..ed69de82468 100644 --- a/bin/varnishtest/tests/c00042.vtc +++ b/bin/varnishtest/tests/c00042.vtc @@ -176,3 +176,9 @@ varnish v1 -errvcl "Cannot stack .via backends" { set bereq.backend = c; } } + +# issue #4177: backend named default with .via property +varnish v1 -vcl { + backend via { .host = "${localhost}"; } + backend default { .via = via; .host = "${localhost}"; } +} diff --git a/lib/libvcc/vcc_backend.c b/lib/libvcc/vcc_backend.c index dc7a64b5929..3cd4da2652d 100644 --- a/lib/libvcc/vcc_backend.c +++ b/lib/libvcc/vcc_backend.c @@ -40,19 +40,6 @@ #include "vcc_compile.h" #include "vus.h" -const char * -vcc_default_probe(struct vcc *tl) -{ - - if (tl->default_probe != NULL) - return (tl->default_probe); - VSB_cat(tl->sb, "No default probe defined\n"); - vcc_ErrToken(tl, tl->t); - VSB_cat(tl->sb, " at\n"); - vcc_ErrWhere(tl, tl->t); - return (""); -} - /*-------------------------------------------------------------------- * Struct sockaddr is not really designed to be a compile time * initialized data structure, so we encode it as a byte-string @@ -346,16 +333,16 @@ vcc_ParseProbe(struct vcc *tl) vcc_ExpectVid(tl, "backend probe"); /* ID: name */ ERRCHK(tl); - if (vcc_IdIs(tl->t, "default")) { - vcc_NextToken(tl); - vcc_ParseProbeSpec(tl, NULL, &p); + + sym = VCC_HandleSymbol(tl, PROBE); + ERRCHK(tl); + AN(sym); + vcc_ParseProbeSpec(tl, sym, &p); + + if (sym->type == DEFAULT) tl->default_probe = p; - } else { - sym = VCC_HandleSymbol(tl, PROBE); - ERRCHK(tl); - AN(sym); - vcc_ParseProbeSpec(tl, sym, NULL); - } + else + free(p); } /*-------------------------------------------------------------------- @@ -370,6 +357,7 @@ vcc_ParseHostDef(struct vcc *tl, struct symbol *sym, { const struct token *t_field; const struct token *t_val; + const struct token *t_probe; const struct token *t_host = NULL; const struct token *t_port = NULL; const struct token *t_path = NULL; @@ -526,16 +514,23 @@ vcc_ParseHostDef(struct vcc *tl, struct symbol *sym, free(p); ERRCHK(tl); } else if (vcc_IdIs(t_field, "probe") && tl->t->tok == ID) { - if (vcc_IdIs(tl->t, "default")) { - vcc_NextToken(tl); - (void)vcc_default_probe(tl); - } else { - pb = VCC_SymbolGet(tl, SYM_MAIN, SYM_PROBE, - SYMTAB_EXISTING, XREF_REF); - ERRCHK(tl); - AN(pb); - Fb(tl, 0, "\t.probe = %s,\n", pb->rname); + t_probe = tl->t; + pb = VCC_SymbolGet(tl, SYM_MAIN, SYM_PROBE, + SYMTAB_EXISTING, XREF_REF); + ERRCHK(tl); + AN(pb); + if (pb->type == DEFAULT) { + if (tl->default_probe == NULL) { + VSB_cat(tl->sb, + "No default probe defined\n"); + vcc_ErrToken(tl, t_probe); + VSB_cat(tl->sb, " at\n"); + vcc_ErrWhere(tl, t_probe); + } + pb = PROBE->default_sym; } + ERRCHK(tl); + Fb(tl, 0, "\t.probe = %s,\n", pb->rname); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "probe")) { VSB_cat(tl->sb, "Expected '{' or name of probe, got "); @@ -720,7 +715,12 @@ vcc_ParseBackend(struct vcc *tl) ERRCHK(tl); t_be = tl->t; - if (vcc_IdIs(tl->t, "default")) { + + sym = VCC_HandleSymbol(tl, BACKEND); + ERRCHK(tl); + AN(sym); + + if (sym->type == DEFAULT) { if (tl->first_director != NULL) { tl->first_director->noref = 0; tl->first_director = NULL; @@ -732,13 +732,9 @@ vcc_ParseBackend(struct vcc *tl) vcc_ErrWhere(tl, t_first); return; } - vcc_NextToken(tl); dn = "vgc_backend_default"; tl->default_director = dn; } else { - sym = VCC_HandleSymbol(tl, BACKEND); - ERRCHK(tl); - AN(sym); dn = sym->rname; if (tl->default_director == NULL) { tl->first_director = sym; @@ -746,6 +742,7 @@ vcc_ParseBackend(struct vcc *tl) sym->noref = 1; } } + Fh(tl, 0, "\nstatic VCL_BACKEND %s;\n", dn); vcc_ParseHostDef(tl, sym, t_be, dn); if (tl->err) { diff --git a/lib/libvcc/vcc_compile.h b/lib/libvcc/vcc_compile.h index 93fb613c8d4..132553241a4 100644 --- a/lib/libvcc/vcc_compile.h +++ b/lib/libvcc/vcc_compile.h @@ -118,6 +118,8 @@ struct type { const char *global_pfx; const char *tostring; vcc_type_t multype; + struct symbol *default_sym; + int stringform; int bodyform; int noindent; @@ -126,6 +128,8 @@ struct type { #define VCC_TYPE(UC, lc) extern const struct type UC[1]; #include "vcc_types.h" +extern const struct type DEFAULT[1]; /* type for pseudo-symbol "default" */ + /*---------------------------------------------------------------------*/ typedef const struct kind *vcc_kind_t; @@ -317,7 +321,6 @@ void vcc_Action_Init(struct vcc *); /* vcc_backend.c */ struct fld_spec; -const char *vcc_default_probe(struct vcc *); void vcc_Backend_Init(struct vcc *tl); void vcc_ParseProbe(struct vcc *tl); void vcc_ParseBackend(struct vcc *tl); diff --git a/lib/libvcc/vcc_expr.c b/lib/libvcc/vcc_expr.c index 7475053aa8e..42089812049 100644 --- a/lib/libvcc/vcc_expr.c +++ b/lib/libvcc/vcc_expr.c @@ -1606,14 +1606,13 @@ vcc_Eval_Default(struct vcc *tl, struct expr **e, struct token *t, (void)sym; (void)t; - if (fmt == PROBE) - *e = vcc_mk_expr(PROBE, "%s", vcc_default_probe(tl)); - else if (fmt == BACKEND) - *e = vcc_mk_expr(BACKEND, "*(VCL_conf.default_director)"); - else { + if (fmt->default_sym == NULL) { VSB_cat(tl->sb, "Symbol 'default' is a reserved word.\n"); vcc_ErrWhere(tl, t); + return; } + + *e = vcc_mk_expr(fmt, "%s", fmt->default_sym->rname); } /*-------------------------------------------------------------------- @@ -1650,6 +1649,6 @@ vcc_Expr_Init(struct vcc *tl) sym = VCC_MkSym(tl, "default", SYM_MAIN, SYM_FUNC, VCL_LOW, VCL_HIGH); AN(sym); - sym->type = BACKEND; // ... can also (sometimes) deliver PROBE + sym->type = DEFAULT; sym->eval = vcc_Eval_Default; } diff --git a/lib/libvcc/vcc_symb.c b/lib/libvcc/vcc_symb.c index fc273f2decf..4d4462cd2ce 100644 --- a/lib/libvcc/vcc_symb.c +++ b/lib/libvcc/vcc_symb.c @@ -363,7 +363,7 @@ VCC_SymbolGet(struct vcc *tl, vcc_ns_t ns, vcc_kind_t kind, vcc_ErrWhere2(tl, t0, tl->t); return (NULL); } - if (kind != SYM_NONE && kind != sym->kind) { + if (kind != SYM_NONE && kind != sym->kind && sym->type != DEFAULT) { VSB_cat(tl->sb, "Symbol '"); vcc_PrintTokens(tl, t0, tl->t); VSB_printf(tl->sb, "' has wrong type (%s), expected %s:", @@ -577,6 +577,11 @@ VCC_HandleSymbol(struct vcc *tl, vcc_type_t fmt) struct token *t; const char *p; + if (vcc_IdIs(tl->t, "default") && fmt->default_sym != NULL) { + vcc_NextToken(tl); + return (fmt->default_sym); + } + kind = VCC_HandleKind(fmt); assert(kind != SYM_NONE); diff --git a/lib/libvcc/vcc_types.c b/lib/libvcc/vcc_types.c index cfa6714b39f..ff0b4e4d439 100644 --- a/lib/libvcc/vcc_types.c +++ b/lib/libvcc/vcc_types.c @@ -67,12 +67,23 @@ static const struct vcc_method backend_methods[] = { { VCC_METHOD_MAGIC, NULL }, }; +static struct symbol default_backend[1] = {{ + .magic = SYMBOL_MAGIC, + .name = "default", + .lorev = 0, + .hirev = 99, + .kind = SYM_BACKEND, + .type = DEFAULT, + .rname = "*(VCL_conf.default_director)", +}}; + const struct type BACKEND[1] = {{ .magic = TYPE_MAGIC, .name = "BACKEND", .methods = backend_methods, .global_pfx = "vgc_backend", .tostring = "VRT_BACKEND_string(\v1)", + .default_sym = default_backend, }}; const struct type BLOB[1] = {{ @@ -101,6 +112,11 @@ const struct type BYTES[1] = {{ .multype = REAL, // XXX: wrong }}; +const struct type DEFAULT[1] = {{ + .magic = TYPE_MAGIC, + .name = "DEFAULT", +}}; + const struct type DURATION[1] = {{ .magic = TYPE_MAGIC, .name = "DURATION", @@ -144,10 +160,21 @@ const struct type IP[1] = {{ .tostring = "VRT_IP_string(ctx, \v1)", }}; +static struct symbol default_probe[1] = {{ + .magic = SYMBOL_MAGIC, + .name = "default", + .lorev = 0, + .hirev = 99, + .kind = SYM_PROBE, + .type = DEFAULT, + .rname = "vgc_probe_default", +}}; + const struct type PROBE[1] = {{ .magic = TYPE_MAGIC, .name = "PROBE", .global_pfx = "vgc_probe", + .default_sym = default_probe, }}; const struct type REAL[1] = {{