void vcc_Eval_Backend(struct vcc *tl, struct expr **e, const struct symbol *sym) { assert(sym->kind == SYM_BACKEND); vcc_ExpectCid(tl); vcc_AddRef(tl, tl->t, SYM_BACKEND); *e = vcc_mk_expr(BACKEND, "VGCDIR(_%.*s)", PF(tl->t)); vcc_NextToken(tl); }
static void parse_call(struct vcc *tl) { vcc_NextToken(tl); ExpectErr(tl, ID); vcc_AddCall(tl, tl->t); vcc_AddRef(tl, tl->t, SYM_SUB); Fb(tl, 1, "if (VGC_function_%.*s(ctx))\n", PF(tl->t)); Fb(tl, 1, "\treturn (1);\n"); vcc_NextToken(tl); }
static void vcc_Function(struct vcc *tl) { int m, i; vcc_NextToken(tl); ExpectErr(tl, ID); m = IsMethod(tl->t); if (m != -1) { assert(m < VCL_MET_MAX); tl->fb = tl->fm[m]; if (tl->mprocs[m] == NULL) { (void)vcc_AddDef(tl, tl->t, SYM_SUB); vcc_AddRef(tl, tl->t, SYM_SUB); tl->mprocs[m] = vcc_AddProc(tl, tl->t); } tl->curproc = tl->mprocs[m]; Fb(tl, 1, " /* ... from "); vcc_Coord(tl, tl->fb, NULL); Fb(tl, 0, " */\n"); } else { tl->fb = tl->fc; i = vcc_AddDef(tl, tl->t, SYM_SUB); if (i > 1) { VSB_printf(tl->sb, "Function %.*s redefined\n", PF(tl->t)); vcc_ErrWhere(tl, tl->t); return; } tl->curproc = vcc_AddProc(tl, tl->t); Fh(tl, 0, "static int VGC_function_%.*s (struct sess *sp);\n", PF(tl->t)); Fc(tl, 1, "\nstatic int\n"); Fc(tl, 1, "VGC_function_%.*s (struct sess *sp)\n", PF(tl->t)); } vcc_NextToken(tl); tl->indent += INDENT; Fb(tl, 1, "{\n"); L(tl, vcc_Compound(tl)); if (m == -1) { /* * non-method subroutines must have an explicit non-action * return in case they just fall through the bottom. */ Fb(tl, 1, " return(0);\n"); } Fb(tl, 1, "}\n"); tl->indent -= INDENT; tl->fb = NULL; tl->curproc = NULL; }
static void parse_call(struct tokenlist *tl) { vcc_NextToken(tl); ExpectErr(tl, ID); vcc_AddCall(tl, tl->t); vcc_AddRef(tl, tl->t, R_FUNC); Fb(tl, 1, "if (VGC_function_%.*s(sp))\n", PF(tl->t)); Fb(tl, 1, "\treturn (1);\n"); vcc_NextToken(tl); return; }
void vcc_ParseProbe(struct vcc *tl) { struct token *t_probe; char *p; vcc_NextToken(tl); /* ID: probe */ vcc_ExpectCid(tl); /* ID: name */ ERRCHK(tl); t_probe = tl->t; vcc_NextToken(tl); (void)VCC_HandleSymbol(tl, t_probe, PROBE, "%.s", PF(t_probe)); ERRCHK(tl); vcc_ParseProbeSpec(tl, t_probe, &p); if (vcc_IdIs(t_probe, "default")) { vcc_AddRef(tl, t_probe, SYM_PROBE); tl->default_probe = p; } }
static void vcc_expr_cmp(struct vcc *tl, struct expr **e, enum var_type fmt) { struct expr *e2; const struct cmps *cp; char buf[256]; char *re; const char *not; struct token *tk; *e = NULL; vcc_expr_add(tl, e, fmt); ERRCHK(tl); if ((*e)->fmt == BOOL) return; tk = tl->t; for (cp = vcc_cmps; cp->fmt != VOID; cp++) if ((*e)->fmt == cp->fmt && tl->t->tok == cp->token) break; if (cp->fmt != VOID) { vcc_NextToken(tl); vcc_expr_add(tl, &e2, (*e)->fmt); ERRCHK(tl); if (e2->fmt != (*e)->fmt) { /* XXX */ VSB_printf(tl->sb, "Comparison of different types: "); VSB_printf(tl->sb, "%s ", vcc_Type((*e)->fmt)); vcc_ErrToken(tl, tk); VSB_printf(tl->sb, " %s\n", vcc_Type(e2->fmt)); vcc_ErrWhere(tl, tk); return; } *e = vcc_expr_edit(BOOL, cp->emit, *e, e2); return; } if ((*e)->fmt == STRING && (tl->t->tok == '~' || tl->t->tok == T_NOMATCH)) { not = tl->t->tok == '~' ? "" : "!"; vcc_NextToken(tl); ExpectErr(tl, CSTR); re = vcc_regexp(tl); ERRCHK(tl); vcc_NextToken(tl); bprintf(buf, "%sVRT_re_match(\v1, %s)", not, re); *e = vcc_expr_edit(BOOL, buf, *e, NULL); return; } if ((*e)->fmt == IP && (tl->t->tok == '~' || tl->t->tok == T_NOMATCH)) { not = tl->t->tok == '~' ? "" : "!"; vcc_NextToken(tl); ExpectErr(tl, ID); vcc_AddRef(tl, tl->t, SYM_ACL); bprintf(buf, "%smatch_acl_named_%.*s(sp, \v1)", not, PF(tl->t)); vcc_NextToken(tl); *e = vcc_expr_edit(BOOL, buf, *e, NULL); return; } if ((*e)->fmt == IP && (tl->t->tok == T_EQ || tl->t->tok == T_NEQ)) { vcc_Acl_Hack(tl, buf); *e = vcc_expr_edit(BOOL, buf, *e, NULL); return; } if ((*e)->fmt == BACKEND && (tl->t->tok == T_EQ || tl->t->tok == T_NEQ)) { vcc_NextToken(tl); ExpectErr(tl, ID); vcc_AddRef(tl, tl->t, SYM_BACKEND); bprintf(buf, "(\v1 %.*s VGCDIR(_%.*s))", PF(tk), PF(tl->t)); vcc_NextToken(tl); *e = vcc_expr_edit(BOOL, buf, *e, NULL); return; } switch (tl->t->tok) { case T_EQ: case T_NEQ: case '<': case T_LEQ: case '>': case T_GEQ: case '~': case T_NOMATCH: VSB_printf(tl->sb, "Operator %.*s not possible on %s\n", PF(tl->t), vcc_Type((*e)->fmt)); vcc_ErrWhere(tl, tl->t); return; default: break; } if (fmt == BOOL && (*e)->fmt == STRING) { *e = vcc_expr_edit(BOOL, "(\v1 != 0)", *e, NULL); return; } }
static void vcc_ParseFunction(struct vcc *tl) { int m, i; vcc_NextToken(tl); vcc_ExpectCid(tl, "function"); ERRCHK(tl); m = IsMethod(tl->t); if (m == -2) { VSB_printf(tl->sb, "VCL sub's named 'vcl*' are reserved names.\n"); vcc_ErrWhere(tl, tl->t); VSB_printf(tl->sb, "Valid vcl_* methods are:\n"); for (i = 1; method_tab[i].name != NULL; i++) VSB_printf(tl->sb, "\t%s\n", method_tab[i].name); return; } else if (m != -1) { assert(m < VCL_MET_MAX); tl->fb = tl->fm[m]; if (tl->mprocs[m] == NULL) { (void)vcc_AddDef(tl, tl->t, SYM_SUB); vcc_AddRef(tl, tl->t, SYM_SUB); tl->mprocs[m] = vcc_AddProc(tl, tl->t); } tl->curproc = tl->mprocs[m]; Fb(tl, 1, " /* ... from "); vcc_Coord(tl, tl->fb, NULL); Fb(tl, 0, " */\n"); } else { tl->fb = tl->fc; i = vcc_AddDef(tl, tl->t, SYM_SUB); if (i > 1) { VSB_printf(tl->sb, "Function '%.*s' redefined\n", PF(tl->t)); vcc_ErrWhere(tl, tl->t); return; } tl->curproc = vcc_AddProc(tl, tl->t); Fh(tl, 0, "int VGC_function_%.*s " "(VRT_CTX);\n", PF(tl->t)); Fc(tl, 1, "\nint __match_proto__(vcl_func_t)\n"); Fc(tl, 1, "VGC_function_%.*s(VRT_CTX)\n", PF(tl->t)); } vcc_NextToken(tl); tl->indent += INDENT; Fb(tl, 1, "{\n"); L(tl, vcc_Compound(tl)); if (m == -1) { /* * non-method subroutines must have an explicit non-action * return in case they just fall through the bottom. */ Fb(tl, 1, " return(0);\n"); } Fb(tl, 1, "}\n"); tl->indent -= INDENT; tl->fb = NULL; tl->curproc = NULL; }
static void parse_set(struct tokenlist *tl) { struct var *vp; struct token *at, *vt; vcc_NextToken(tl); ExpectErr(tl, VAR); vt = tl->t; vp = vcc_FindVar(tl, tl->t, vcc_vars); ERRCHK(tl); assert(vp != NULL); check_writebit(tl, vp); ERRCHK(tl); Fb(tl, 1, "%s", vp->lname); vcc_NextToken(tl); switch (vp->fmt) { case INT: case SIZE: case TIME: case RTIME: case FLOAT: if (tl->t->tok != '=') Fb(tl, 0, "%s %c ", vp->rname, *tl->t->b); at = tl->t; vcc_NextToken(tl); switch (at->tok) { case T_MUL: case T_DIV: Fb(tl, 0, "%g", vcc_DoubleVal(tl)); break; case T_INCR: case T_DECR: case '=': vcc_VarVal(tl, vp, vt); ERRCHK(tl); break; default: vsb_printf(tl->sb, "Invalid assignment operator.\n"); vcc_ErrWhere(tl, at); return; } Fb(tl, 0, ");\n"); break; #if 0 /* XXX: enable if we find a legit use */ case IP: if (tl->t->tok != '=') { illegal_assignment(tl, "IP numbers"); return; } vcc_NextToken(tl); u = vcc_vcc_IpVal(tl); Fb(tl, 0, "= %uU; /* %u.%u.%u.%u */\n", u, (u >> 24) & 0xff, (u >> 16) & 0xff, (u >> 8) & 0xff, u & 0xff); break; #endif case BACKEND: if (tl->t->tok != '=') { illegal_assignment(tl, "backend"); return; } vcc_NextToken(tl); vcc_ExpectCid(tl); ERRCHK(tl); vcc_AddRef(tl, tl->t, R_BACKEND); Fb(tl, 0, "VGCDIR(_%.*s)", PF(tl->t)); vcc_NextToken(tl); Fb(tl, 0, ");\n"); break; case HASH: SkipToken(tl, T_INCR); if (!vcc_StringVal(tl)) { ERRCHK(tl); vcc_ExpectedStringval(tl); return; } Fb(tl, 0, ");\n"); /* * We count the number of operations on the req.hash * variable, so that varnishd can preallocate the worst case * number of slots for composing the hash string. */ break; case STRING: if (tl->t->tok != '=') { illegal_assignment(tl, "strings"); return; } vcc_NextToken(tl); if (!vcc_StringVal(tl)) { ERRCHK(tl); vcc_ExpectedStringval(tl); return; } do Fb(tl, 0, ", "); while (vcc_StringVal(tl)); if (tl->t->tok != ';') { ERRCHK(tl); vsb_printf(tl->sb, "Expected variable, string or semicolon\n"); vcc_ErrWhere(tl, tl->t); return; } Fb(tl, 0, "vrt_magic_string_end);\n"); break; case BOOL: if (tl->t->tok != '=') { illegal_assignment(tl, "boolean"); return; } vcc_NextToken(tl); ExpectErr(tl, ID); if (vcc_IdIs(tl->t, "true")) { Fb(tl, 0, " 1);\n", vp->lname); } else if (vcc_IdIs(tl->t, "false")) { Fb(tl, 0, " 0);\n", vp->lname); } else { vsb_printf(tl->sb, "Expected true or false\n"); vcc_ErrWhere(tl, tl->t); return; } vcc_NextToken(tl); break; default: vsb_printf(tl->sb, "Assignments not possible for type of '%s'\n", vp->name); vcc_ErrWhere(tl, tl->t); return; } }
static void vcc_ParseHostDef(struct vcc *tl, const struct token *t_be, const char *vgcname) { struct token *t_field; struct token *t_val; struct token *t_host = NULL; struct token *t_port = NULL; struct token *t_hosthdr = NULL; struct fld_spec *fs; struct inifin *ifp; struct vsb *vsb; char *p; unsigned u; double t; fs = vcc_FldSpec(tl, "!host", "?port", "?host_header", "?connect_timeout", "?first_byte_timeout", "?between_bytes_timeout", "?probe", "?max_connections", "?proxy_header", NULL); SkipToken(tl, '{'); vsb = VSB_new_auto(); AN(vsb); tl->fb = vsb; Fb(tl, 0, "\nstatic const struct vrt_backend vgc_dir_priv_%s = {\n", vgcname); Fb(tl, 0, "\t.magic = VRT_BACKEND_MAGIC,\n"); Fb(tl, 0, "\t.vcl_name = \"%.*s", PF(t_be)); Fb(tl, 0, "\",\n"); /* Check for old syntax */ if (tl->t->tok == ID && vcc_IdIs(tl->t, "set")) { VSB_printf(tl->sb, "NB: Backend Syntax has changed:\n" "Remove \"set\" and \"backend\" in front" " of backend fields.\n" ); vcc_ErrToken(tl, tl->t); VSB_printf(tl->sb, " at "); vcc_ErrWhere(tl, tl->t); return; } while (tl->t->tok != '}') { vcc_IsField(tl, &t_field, fs); ERRCHK(tl); if (vcc_IdIs(t_field, "host")) { ExpectErr(tl, CSTR); assert(tl->t->dec != NULL); t_host = tl->t; vcc_NextToken(tl); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "port")) { ExpectErr(tl, CSTR); assert(tl->t->dec != NULL); t_port = tl->t; vcc_NextToken(tl); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "host_header")) { ExpectErr(tl, CSTR); assert(tl->t->dec != NULL); t_hosthdr = tl->t; vcc_NextToken(tl); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "connect_timeout")) { Fb(tl, 0, "\t.connect_timeout = "); vcc_Duration(tl, &t); ERRCHK(tl); Fb(tl, 0, "%g,\n", t); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "first_byte_timeout")) { Fb(tl, 0, "\t.first_byte_timeout = "); vcc_Duration(tl, &t); ERRCHK(tl); Fb(tl, 0, "%g,\n", t); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "between_bytes_timeout")) { Fb(tl, 0, "\t.between_bytes_timeout = "); vcc_Duration(tl, &t); ERRCHK(tl); Fb(tl, 0, "%g,\n", t); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "max_connections")) { u = vcc_UintVal(tl); ERRCHK(tl); SkipToken(tl, ';'); Fb(tl, 0, "\t.max_connections = %u,\n", u); } else if (vcc_IdIs(t_field, "proxy_header")) { t_val = tl->t; u = vcc_UintVal(tl); ERRCHK(tl); if (u != 1 && u != 2) { VSB_printf(tl->sb, ".proxy_header must be 1 or 2\n"); vcc_ErrWhere(tl, t_val); return; } SkipToken(tl, ';'); Fb(tl, 0, "\t.proxy_header = %u,\n", u); } else if (vcc_IdIs(t_field, "probe") && tl->t->tok == '{') { vcc_ParseProbeSpec(tl, NULL, &p); Fb(tl, 0, "\t.probe = &%s,\n", p); ERRCHK(tl); } else if (vcc_IdIs(t_field, "probe") && tl->t->tok == ID) { if (VCC_FindSymbol(tl, tl->t, SYM_PROBE) == NULL) { VSB_printf(tl->sb, "Probe %.*s not found\n", PF(tl->t)); vcc_ErrWhere(tl, tl->t); return; } Fb(tl, 0, "\t.probe = &vgc_probe_%.*s,\n", PF(tl->t)); vcc_AddRef(tl, tl->t, SYM_PROBE); vcc_NextToken(tl); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "probe")) { VSB_printf(tl->sb, "Expected '{' or name of probe, got "); vcc_ErrToken(tl, tl->t); VSB_printf(tl->sb, " at\n"); vcc_ErrWhere(tl, tl->t); return; } else { ErrInternal(tl); return; } } vcc_FieldsOk(tl, fs); ERRCHK(tl); /* Check that the hostname makes sense */ assert(t_host != NULL); Emit_Sockaddr(tl, t_host, t_port); ERRCHK(tl); ExpectErr(tl, '}'); /* We have parsed it all, emit the ident string */ /* Emit the hosthdr field, fall back to .host if not specified */ Fb(tl, 0, "\t.hosthdr = "); if (t_hosthdr != NULL) EncToken(tl->fb, t_hosthdr); else EncToken(tl->fb, t_host); Fb(tl, 0, ",\n"); /* Close the struct */ Fb(tl, 0, "};\n"); vcc_NextToken(tl); tl->fb = NULL; AZ(VSB_finish(vsb)); Fh(tl, 0, "%s", VSB_data(vsb)); VSB_destroy(&vsb); ifp = New_IniFin(tl); VSB_printf(ifp->ini, "\t%s =\n\t VRT_new_backend(ctx, &vgc_dir_priv_%s);", vgcname, vgcname); }
static void vcc_ParseHostDef(struct vcc *tl, int serial, const char *vgcname) { struct token *t_field; struct token *t_host = NULL; struct token *t_port = NULL; struct token *t_hosthdr = NULL; unsigned saint = UINT_MAX; struct fld_spec *fs; struct vsb *vsb; unsigned u; double t; Fh(tl, 1, "\n#define VGC_backend_%s %d\n", vgcname, tl->ndirector); fs = vcc_FldSpec(tl, "!host", "?port", "?host_header", "?connect_timeout", "?first_byte_timeout", "?between_bytes_timeout", "?probe", "?max_connections", "?saintmode_threshold", NULL); SkipToken(tl, '{'); vsb = VSB_new_auto(); AN(vsb); tl->fb = vsb; Fb(tl, 0, "\nstatic const struct vrt_backend vgc_dir_priv_%s = {\n", vgcname); Fb(tl, 0, "\t.vcl_name = \"%.*s", PF(tl->t_dir)); if (serial >= 0) Fb(tl, 0, "[%d]", serial); Fb(tl, 0, "\",\n"); /* Check for old syntax */ if (tl->t->tok == ID && vcc_IdIs(tl->t, "set")) { VSB_printf(tl->sb, "NB: Backend Syntax has changed:\n" "Remove \"set\" and \"backend\" in front" " of backend fields.\n" ); vcc_ErrToken(tl, tl->t); VSB_printf(tl->sb, " at "); vcc_ErrWhere(tl, tl->t); return; } while (tl->t->tok != '}') { vcc_IsField(tl, &t_field, fs); ERRCHK(tl); if (vcc_IdIs(t_field, "host")) { ExpectErr(tl, CSTR); assert(tl->t->dec != NULL); t_host = tl->t; vcc_NextToken(tl); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "port")) { ExpectErr(tl, CSTR); assert(tl->t->dec != NULL); t_port = tl->t; vcc_NextToken(tl); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "host_header")) { ExpectErr(tl, CSTR); assert(tl->t->dec != NULL); t_hosthdr = tl->t; vcc_NextToken(tl); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "connect_timeout")) { Fb(tl, 0, "\t.connect_timeout = "); vcc_Duration(tl, &t); ERRCHK(tl); Fb(tl, 0, "%g,\n", t); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "first_byte_timeout")) { Fb(tl, 0, "\t.first_byte_timeout = "); vcc_Duration(tl, &t); ERRCHK(tl); Fb(tl, 0, "%g,\n", t); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "between_bytes_timeout")) { Fb(tl, 0, "\t.between_bytes_timeout = "); vcc_Duration(tl, &t); ERRCHK(tl); Fb(tl, 0, "%g,\n", t); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "max_connections")) { u = vcc_UintVal(tl); ERRCHK(tl); SkipToken(tl, ';'); Fb(tl, 0, "\t.max_connections = %u,\n", u); } else if (vcc_IdIs(t_field, "saintmode_threshold")) { u = vcc_UintVal(tl); /* UINT_MAX == magic number to mark as unset, so * not allowed here. */ if (u == UINT_MAX) { VSB_printf(tl->sb, "Value outside allowed range: "); vcc_ErrToken(tl, tl->t); VSB_printf(tl->sb, " at\n"); vcc_ErrWhere(tl, tl->t); } ERRCHK(tl); saint = u; SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "probe") && tl->t->tok == '{') { Fb(tl, 0, "\t.probe = &vgc_probe__%d,\n", tl->nprobe); vcc_ParseProbeSpec(tl); ERRCHK(tl); } else if (vcc_IdIs(t_field, "probe") && tl->t->tok == ID) { Fb(tl, 0, "\t.probe = &vgc_probe_%.*s,\n", PF(tl->t)); vcc_AddRef(tl, tl->t, SYM_PROBE); vcc_NextToken(tl); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "probe")) { VSB_printf(tl->sb, "Expected '{' or name of probe."); vcc_ErrToken(tl, tl->t); VSB_printf(tl->sb, " at\n"); vcc_ErrWhere(tl, tl->t); return; } else { ErrInternal(tl); return; } } vcc_FieldsOk(tl, fs); ERRCHK(tl); /* Check that the hostname makes sense */ assert(t_host != NULL); if (t_port != NULL) Emit_Sockaddr(tl, t_host, t_port->dec); else Emit_Sockaddr(tl, t_host, "80"); ERRCHK(tl); ExpectErr(tl, '}'); /* We have parsed it all, emit the ident string */ /* Emit the hosthdr field, fall back to .host if not specified */ Fb(tl, 0, "\t.hosthdr = "); if (t_hosthdr != NULL) EncToken(tl->fb, t_hosthdr); else EncToken(tl->fb, t_host); Fb(tl, 0, ",\n"); Fb(tl, 0, "\t.saintmode_threshold = %d,\n",saint); /* Close the struct */ Fb(tl, 0, "};\n"); vcc_NextToken(tl); tl->fb = NULL; AZ(VSB_finish(vsb)); Fh(tl, 0, "%s", VSB_data(vsb)); VSB_delete(vsb); Fi(tl, 0, "\tVRT_init_dir(cli, VCL_conf.director, \"simple\",\n" "\t VGC_backend_%s, &vgc_dir_priv_%s);\n", vgcname, vgcname); Ff(tl, 0, "\tVRT_fini_dir(cli, VGCDIR(%s));\n", vgcname); tl->ndirector++; }