varnish-cache/lib/libvcc/vcc_action.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2015 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 * This file parses the real action of the VCL code, the procedure
30
 * statements which do the actual work.
31
 */
32
33
#include "config.h"
34
35
#include <string.h>
36
37
#include "vcc_compile.h"
38
#include "libvcc.h"
39
40
/*--------------------------------------------------------------------*/
41
42
static void v_matchproto_(sym_act_f)
43 13
vcc_act_call(struct vcc *tl, struct token *t, struct symbol *sym)
44
{
45
46
        (void)t;
47 13
        ExpectErr(tl, ID);
48 13
        sym = VCC_SymbolGet(tl, SYM_SUB, SYMTAB_CREATE, XREF_REF);
49 13
        AN(sym);
50 13
        vcc_AddCall(tl, sym);
51 13
        VCC_GlobalSymbol(sym, SUB, "VGC_function");
52 13
        Fb(tl, 1, "%s(ctx);\n", sym->rname);
53 13
        SkipToken(tl, ';');
54
}
55
56
/*--------------------------------------------------------------------*/
57
58
static const struct arith {
59
        vcc_type_t              type;
60
        unsigned                oper;
61
        vcc_type_t              want;
62
} arith[] = {
63
        { INT,          T_INCR,         INT },
64
        { INT,          T_DECR,         INT },
65
        { INT,          T_MUL,          INT },
66
        { INT,          T_DIV,          INT },
67
        { INT,          '=',            INT },
68
        { INT,          0,              INT },
69
        { TIME,         T_INCR,         DURATION },
70
        { TIME,         T_DECR,         DURATION },
71
        { TIME,         T_MUL,          REAL },
72
        { TIME,         T_DIV,          REAL },
73
        { TIME,         '=',            TIME },
74
        { TIME,         0,              TIME },
75
        { DURATION,     T_INCR,         DURATION },
76
        { DURATION,     T_DECR,         DURATION },
77
        { DURATION,     T_MUL,          REAL },
78
        { DURATION,     T_DIV,          REAL },
79
        { DURATION,     '=',            DURATION },
80
        { DURATION,     0,              DURATION },
81
        { VOID,         '=',            VOID }
82
};
83
84
85
/*--------------------------------------------------------------------*/
86
87
static void v_matchproto_(sym_act_f)
88 9073
vcc_act_set(struct vcc *tl, struct token *t, struct symbol *sym)
89
{
90
        const struct arith *ap;
91
        vcc_type_t type;
92
93
        (void)t;
94 9073
        ExpectErr(tl, ID);
95 9073
        t = tl->t;
96 9073
        sym = VCC_SymbolGet(tl, SYM_VAR, "Unknown variable", XREF_NONE);
97 9073
        ERRCHK(tl);
98 9067
        AN(sym);
99 9067
        if (sym->w_methods == 0) {
100 6
                vcc_ErrWhere2(tl, t, tl->t);
101 6
                if (sym->r_methods != 0)
102 5
                        VSB_printf(tl->sb, "Variable is read only.\n");
103
                else
104 1
                        VSB_printf(tl->sb, "Variable cannot be set.\n");
105 6
                return;
106
        }
107 9061
        vcc_AddUses(tl, t, tl->t, sym->w_methods, "Cannot be set");
108 9061
        Fb(tl, 1, "%s\n", sym->lname);
109 9061
        tl->indent += INDENT;
110 9061
        type = sym->type;
111 169562
        for (ap = arith; ap->type != VOID; ap++) {
112 161564
                if (ap->type != type)
113 156258
                        continue;
114 5306
                if (ap->oper != tl->t->tok)
115 4243
                        continue;
116 1063
                if (ap->oper != '=')
117 5
                        Fb(tl, 1, "%s %c ", sym->rname, *tl->t->b);
118 1063
                vcc_NextToken(tl);
119 1063
                type = ap->want;
120 1063
                break;
121
        }
122 9061
        if (ap->type == VOID)
123 7998
                SkipToken(tl, ap->oper);
124 9057
        if (type == HEADER) {
125 4934
                vcc_Expr(tl, STRING_LIST);
126 4123
        } else if (type == STRING) {
127 50
                vcc_Expr(tl, STRING_LIST);
128 4073
        } else if (type == BODY) {
129 1798
                vcc_Expr(tl, STRING_LIST);
130
        } else {
131 2275
                vcc_Expr(tl, type);
132
        }
133 9057
        ERRCHK(tl);
134 9024
        tl->indent -= INDENT;
135 9024
        Fb(tl, 1, ");\n");
136 9024
        SkipToken(tl, ';');
137
}
138
139
/*--------------------------------------------------------------------*/
140
141
static void v_matchproto_(sym_act_f)
142 926
vcc_act_unset(struct vcc *tl, struct token *t, struct symbol *sym)
143
{
144
145
        /* XXX: Wrong, should use VCC_Expr(HEADER) */
146 926
        ExpectErr(tl, ID);
147 926
        t = tl->t;
148 926
        sym = VCC_SymbolGet(tl, SYM_VAR, "Unknown variable", XREF_NONE);
149 926
        ERRCHK(tl);
150 926
        AN(sym);
151 926
        if (sym->u_methods == 0) {
152 1
                vcc_ErrWhere2(tl, t, tl->t);
153 1
                VSB_printf(tl->sb, "Variable cannot be unset.\n");
154 1
                return;
155
        }
156 925
        vcc_AddUses(tl, t, tl->t, sym->u_methods, "Cannot be unset");
157 925
        Fb(tl, 1, "%s;\n", sym->uname);
158 925
        SkipToken(tl, ';');
159
}
160
161
/*--------------------------------------------------------------------*/
162
163
static void v_matchproto_(sym_act_f)
164 15
vcc_act_ban(struct vcc *tl, struct token *t, struct symbol *sym)
165
{
166
167
        (void)t;
168
        (void)sym;
169
170 15
        ExpectErr(tl, '(');
171 15
        vcc_NextToken(tl);
172
173 15
        Fb(tl, 1, "VRT_ban_string(ctx, \n");
174 15
        tl->indent += INDENT;
175 15
        vcc_Expr(tl, STRING);
176 15
        tl->indent -= INDENT;
177 15
        ERRCHK(tl);
178 14
        Fb(tl, 1, ");\n");
179
180 14
        SkipToken(tl, ')');
181 14
        SkipToken(tl, ';');
182
}
183
184
/*--------------------------------------------------------------------*/
185
186
static void v_matchproto_(sym_act_f)
187 2694
vcc_act_hash_data(struct vcc *tl, struct token *t, struct symbol *sym)
188
{
189
190
        (void)t;
191
        (void)sym;
192 2694
        SkipToken(tl, '(');
193
194 2694
        Fb(tl, 1, "VRT_hashdata(ctx,\n  ");
195 2694
        vcc_Expr(tl, STRING_LIST);
196 2694
        ERRCHK(tl);
197 2693
        Fb(tl, 1, ");\n");
198 2693
        SkipToken(tl, ')');
199 2693
        SkipToken(tl, ';');
200
}
201
202
/*--------------------------------------------------------------------*/
203
204
static void
205 4
vcc_act_return_pass(struct vcc *tl)
206
{
207
208 4
        ExpectErr(tl, '(');
209 4
        vcc_NextToken(tl);
210 4
        Fb(tl, 1, "VRT_hit_for_pass(ctx,\n");
211 4
        tl->indent += INDENT;
212 4
        vcc_Expr(tl, DURATION);
213 4
        ERRCHK(tl);
214 4
        SkipToken(tl, ')');
215 4
        Fb(tl, 1, ");\n");
216 4
        tl->indent -= INDENT;
217
}
218
/*--------------------------------------------------------------------*/
219
220
static void
221 2796
vcc_act_return_synth(struct vcc *tl)
222
{
223
224 2796
        ExpectErr(tl, '(');
225 2796
        vcc_NextToken(tl);
226 2796
        Fb(tl, 1, "VRT_synth(ctx,\n");
227 2796
        tl->indent += INDENT;
228 2796
        vcc_Expr(tl, INT);
229 2796
        ERRCHK(tl);
230 2796
        Fb(tl, 1, ",\n");
231 2796
        if (tl->t->tok == ',') {
232 922
                vcc_NextToken(tl);
233 922
                vcc_Expr(tl, STRING);
234 922
                ERRCHK(tl);
235
        } else {
236 1874
                Fb(tl, 1, "(const char*)0\n");
237
        }
238 2796
        tl->indent -= INDENT;
239 2796
        SkipToken(tl, ')');
240 2796
        Fb(tl, 1, ");\n");
241
}
242
243
/*--------------------------------------------------------------------*/
244
245
static void
246 18
vcc_act_return_vcl(struct vcc *tl)
247
{
248
        struct symbol *sym;
249
        struct inifin *p;
250
        char buf[1024];
251
252 20
        ExpectErr(tl, '(');
253 18
        vcc_NextToken(tl);
254 18
        ExpectErr(tl, ID);
255 18
        sym = VCC_SymbolGet(tl, SYM_VCL, "Not a VCL label", XREF_NONE);
256 18
        ERRCHK(tl);
257 16
        AN(sym);
258 16
        if (sym->eval_priv == NULL) {
259 16
                VSB_printf(tl->fi, "%s VCL %s */\n", VCC_INFO_PREFIX,
260
                    sym->name);
261
262 16
                bprintf(buf, "vgc_vcl_%u", tl->unique++);
263 16
                sym->eval_priv = strdup(buf);
264 16
                AN(sym->eval_priv);
265
266 16
                Fh(tl, 0, "static VCL_VCL %s;", buf);
267 16
                Fh(tl, 0, "\t/* VCL %s */\n", sym->name);
268
269 16
                p = New_IniFin(tl);
270 16
                AN(p);
271 16
                VSB_printf(p->ini, "\t%s = VRT_vcl_get(ctx, \"%s\");",
272
                    buf, sym->name);
273 16
                VSB_printf(p->fin, "\tVRT_vcl_rel(ctx, %s);",
274
                    buf);
275
        }
276 32
        Fb(tl, 1, "VRT_vcl_select(ctx, %s);\t/* %s */\n",
277 16
            (const char*)sym->eval_priv, sym->name);
278 16
        SkipToken(tl, ')');
279
}
280
281
/*--------------------------------------------------------------------*/
282
283
static void v_matchproto_(sym_act_f)
284 20039
vcc_act_return(struct vcc *tl, struct token *t, struct symbol *sym)
285
{
286
        unsigned hand;
287
        const char *h;
288
289
        (void)t;
290
        (void)sym;
291 20039
        AN(tl->curproc);
292 20039
        if (tl->t->tok == ';' && tl->curproc->method == NULL) {
293 1
                SkipToken(tl, ';');
294 1
                Fb(tl, 1, "return;\n");
295 1
                return;
296
        }
297 20038
        SkipToken(tl, '(');
298 20037
        ExpectErr(tl, ID);
299
300 20037
        hand = VCL_RET_MAX;
301 20037
        h = NULL;
302
#define VCL_RET_MAC(l, U, B)                            \
303
                if (vcc_IdIs(tl->t, #l)) {              \
304
                        hand = VCL_RET_ ## U;           \
305
                        h = #U;                         \
306
                }
307
#include "tbl/vcl_returns.h"
308 20037
        if (h == NULL) {
309 1
                VSB_printf(tl->sb, "Expected return action name.\n");
310 1
                vcc_ErrWhere(tl, tl->t);
311 1
                ERRCHK(tl);
312
        }
313 20036
        assert(hand < VCL_RET_MAX);
314
315 20036
        vcc_ProcAction(tl->curproc, hand, tl->t);
316 20036
        vcc_NextToken(tl);
317 20036
        if (tl->t->tok == '(') {
318 2819
                if (hand == VCL_RET_SYNTH)
319 2796
                        vcc_act_return_synth(tl);
320 23
                else if (hand == VCL_RET_VCL)
321 18
                        vcc_act_return_vcl(tl);
322 5
                else if (hand == VCL_RET_PASS)
323 4
                        vcc_act_return_pass(tl);
324
                else {
325 1
                        VSB_printf(tl->sb, "Arguments not allowed.\n");
326 1
                        vcc_ErrWhere(tl, tl->t);
327
                }
328
        } else {
329 17217
                if (hand == VCL_RET_SYNTH || hand == VCL_RET_VCL) {
330 1
                        VSB_printf(tl->sb, "Missing argument.\n");
331 1
                        vcc_ErrWhere(tl, tl->t);
332
                }
333
        }
334 20036
        ERRCHK(tl);
335 20032
        Fb(tl, 1, "VRT_handling(ctx, VCL_RET_%s);\n", h);
336 20032
        SkipToken(tl, ')');
337 20032
        SkipToken(tl, ';');
338
}
339
340
/*--------------------------------------------------------------------*/
341
342
static void v_matchproto_(sym_act_f)
343 3
vcc_act_synthetic(struct vcc *tl, struct token *t, struct symbol *sym)
344
{
345
346
        (void)t;
347
        (void)sym;
348 3
        ExpectErr(tl, '(');
349 3
        ERRCHK(tl);
350 3
        vcc_NextToken(tl);
351
352 3
        Fb(tl, 1, "VRT_synth_page(ctx, ");
353 3
        vcc_Expr(tl, STRING_LIST);
354 3
        ERRCHK(tl);
355 2
        Fb(tl, 1, ");\n");
356
357 2
        SkipToken(tl, ')');
358 2
        SkipToken(tl, ';');
359
}
360
361
/*--------------------------------------------------------------------*/
362
363
// The pp[] trick is to make the length of #name visible to flexelint.
364
#define ACT(name, func, mask)                                           \
365
        do {                                                            \
366
                const char pp[] = #name;                                \
367
                sym = VCC_MkSym(tl, pp, SYM_ACTION, VCL_LOW, VCL_HIGH); \
368
                AN(sym);                                                \
369
                sym->action = func;                                     \
370
                sym->action_mask = (mask);                              \
371
        } while (0)
372
373
void
374 1063
vcc_Action_Init(struct vcc *tl)
375
{
376
        struct symbol *sym;
377
378 1063
        ACT(ban,        vcc_act_ban,    0);
379 1063
        ACT(call,       vcc_act_call,   0);
380 1063
        ACT(hash_data,  vcc_act_hash_data,
381
                VCL_MET_HASH);
382 1063
        ACT(if,         vcc_Act_If,     0);
383 1063
        ACT(new,        vcc_Act_New,
384
                VCL_MET_INIT);
385 1063
        ACT(return,     vcc_act_return, 0);
386 1063
        ACT(set,        vcc_act_set,    0);
387 1063
        ACT(synthetic,  vcc_act_synthetic,
388
                VCL_MET_SYNTH | VCL_MET_BACKEND_ERROR);
389 1063
        ACT(unset,      vcc_act_unset,  0);
390 1063
}