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
43 24
parse_call(struct vcc *tl)
44
{
45
        struct symbol *sym;
46
47 24
        vcc_NextToken(tl);
48 48
        ExpectErr(tl, ID);
49 24
        vcc_AddCall(tl, tl->t);
50 24
        sym = vcc_AddRef(tl, tl->t, SYM_SUB);
51 24
        VCC_GlobalSymbol(sym, SUB, "VGC_function");
52 24
        Fb(tl, 1, "%s(ctx);\n", sym->rname);
53 24
        vcc_NextToken(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
static void
85 15606
parse_set(struct vcc *tl)
86
{
87
        const struct symbol *sym;
88
        const struct arith *ap;
89
        vcc_type_t fmt;
90
91 15606
        vcc_NextToken(tl);
92 15606
        ExpectErr(tl, ID);
93 15606
        sym = vcc_FindVar(tl, tl->t, 1, "cannot be set");
94 15606
        ERRCHK(tl);
95 15592
        assert(sym != NULL);
96 15592
        if (vcc_IdIs(tl->t, "bereq.body")) {
97 2
                VSB_printf(tl->sb, "bereq.body cannot be set.\n");
98 2
                vcc_ErrWhere(tl, tl->t);
99 2
                return;
100
        }
101 15590
        Fb(tl, 1, "%s\n", sym->lname);
102 15590
        tl->indent += INDENT;
103 15590
        vcc_NextToken(tl);
104 15590
        fmt = sym->fmt;
105 291708
        for (ap = arith; ap->type != VOID; ap++) {
106 277946
                if (ap->type != fmt)
107 268824
                        continue;
108 9122
                if (ap->oper != tl->t->tok)
109 7294
                        continue;
110 1828
                if (ap->oper != '=')
111 10
                        Fb(tl, 1, "%s %c ", sym->rname, *tl->t->b);
112 1828
                vcc_NextToken(tl);
113 1828
                fmt = ap->want;
114 1828
                break;
115
        }
116 15590
        if (ap->type == VOID)
117 13762
                SkipToken(tl, ap->oper);
118 15582
        if (fmt == HEADER) {
119 8466
                vcc_Expr(tl, STRING_LIST);
120 7116
        } else if (fmt == STRING) {
121 86
                vcc_Expr(tl, STRING_LIST);
122 7030
        } else if (fmt == BODY) {
123 3080
                vcc_Expr(tl, STRING_LIST);
124
        } else {
125 3950
                vcc_Expr(tl, fmt);
126
        }
127 15582
        tl->indent -= INDENT;
128 15582
        Fb(tl, 1, ");\n");
129
}
130
131
/*--------------------------------------------------------------------*/
132
133
static void
134 1602
parse_unset(struct vcc *tl)
135
{
136
        const struct symbol *sym;
137
138
        /* XXX: Wrong, should use VCC_Expr(HEADER) */
139 1602
        vcc_NextToken(tl);
140 1602
        ExpectErr(tl, ID);
141 1602
        sym = vcc_FindVar(tl, tl->t, 1, "cannot be unset");
142 1602
        ERRCHK(tl);
143 1602
        assert(sym != NULL);
144 1602
        if (sym->fmt != HEADER && !vcc_IdIs(tl->t, "bereq.body")) {
145 2
                VSB_printf(tl->sb,
146
                    "Only bereq.body and HTTP header variables can"
147
                    " be unset.\n");
148 2
                vcc_ErrWhere(tl, tl->t);
149 2
                return;
150
        }
151 1600
        ERRCHK(tl);
152 1600
        Fb(tl, 1, "%svrt_magic_string_unset);\n", sym->lname);
153 1600
        vcc_NextToken(tl);
154
}
155
156
/*--------------------------------------------------------------------*/
157
158
static void
159 30
parse_ban(struct vcc *tl)
160
{
161
162 30
        vcc_NextToken(tl);
163
164 30
        ExpectErr(tl, '(');
165 30
        vcc_NextToken(tl);
166
167 30
        Fb(tl, 1, "VRT_ban_string(ctx, \n");
168 30
        tl->indent += INDENT;
169 30
        vcc_Expr(tl, STRING);
170 30
        tl->indent -= INDENT;
171 30
        ERRCHK(tl);
172 28
        Fb(tl, 1, ");\n");
173
174 28
        ExpectErr(tl, ')');
175 28
        vcc_NextToken(tl);
176
}
177
178
/*--------------------------------------------------------------------*/
179
180
static void
181 4634
parse_hash_data(struct vcc *tl)
182
{
183 4634
        vcc_NextToken(tl);
184 4634
        SkipToken(tl, '(');
185
186 4634
        Fb(tl, 1, "VRT_hashdata(ctx,\n  ");
187 4634
        vcc_Expr(tl, STRING_LIST);
188 4634
        ERRCHK(tl);
189 4632
        Fb(tl, 1, ");\n");
190 4632
        SkipToken(tl, ')');
191
}
192
193
/*--------------------------------------------------------------------*/
194
195
static void
196 8
parse_return_pass(struct vcc *tl)
197
{
198
199 8
        ExpectErr(tl, '(');
200 8
        vcc_NextToken(tl);
201 8
        Fb(tl, 1, "VRT_hit_for_pass(ctx,\n");
202 8
        tl->indent += INDENT;
203 8
        vcc_Expr(tl, DURATION);
204 8
        ERRCHK(tl);
205 8
        ExpectErr(tl, ')');
206 8
        vcc_NextToken(tl);
207 8
        Fb(tl, 1, ");\n");
208 8
        tl->indent -= INDENT;
209
}
210
/*--------------------------------------------------------------------*/
211
212
static void
213 3256
parse_return_synth(struct vcc *tl)
214
{
215
216 3256
        ExpectErr(tl, '(');
217 3256
        vcc_NextToken(tl);
218 3256
        Fb(tl, 1, "VRT_synth(ctx,\n");
219 3256
        tl->indent += INDENT;
220 3256
        vcc_Expr(tl, INT);
221 3256
        ERRCHK(tl);
222 3256
        Fb(tl, 1, ",\n");
223 3256
        if (tl->t->tok == ',') {
224 1588
                vcc_NextToken(tl);
225 1588
                vcc_Expr(tl, STRING);
226 1588
                ERRCHK(tl);
227
        } else {
228 1668
                Fb(tl, 1, "(const char*)0\n");
229
        }
230 3256
        tl->indent -= INDENT;
231 3256
        ExpectErr(tl, ')');
232 3256
        vcc_NextToken(tl);
233 3256
        Fb(tl, 1, ");\n");
234
}
235
236
/*--------------------------------------------------------------------*/
237
238
static void
239 32
parse_return_vcl(struct vcc *tl)
240
{
241
        struct symbol *sym;
242
        struct inifin *p;
243
        char buf[1024];
244
245 32
        ExpectErr(tl, '(');
246 32
        vcc_NextToken(tl);
247 32
        ExpectErr(tl, ID);
248 32
        sym = VCC_SymbolTok(tl, NULL, tl->t, SYM_VCL, 0);
249 32
        ERRCHK(tl);
250 32
        if (sym == NULL) {
251 0
                VSB_printf(tl->sb, "Not a VCL label:\n");
252 0
                vcc_ErrWhere(tl, tl->t);
253 0
                return;
254
        }
255 32
        if (sym->eval_priv == NULL) {
256 32
                VSB_printf(tl->fi, "%s VCL %s */\n", VCC_INFO_PREFIX,
257
                    sym->name);
258
259 32
                bprintf(buf, "vgc_vcl_%u", tl->unique++);
260 32
                sym->eval_priv = strdup(buf);
261 32
                AN(sym->eval_priv);
262
263 32
                Fh(tl, 0, "static VCL_VCL %s;", buf);
264 32
                Fh(tl, 0, "\t/* VCL %s */\n", sym->name);
265
266 32
                p = New_IniFin(tl);
267 32
                AN(p);
268 32
                VSB_printf(p->ini, "\t%s = VRT_vcl_get(ctx, \"%s\");",
269
                    buf, sym->name);
270 32
                VSB_printf(p->fin, "\tVRT_vcl_rel(ctx, %s);",
271
                    buf);
272
        }
273 64
        Fb(tl, 1, "VRT_vcl_select(ctx, %s);\t/* %s */\n",
274 32
            (const char*)sym->eval_priv, sym->name);
275 32
        vcc_NextToken(tl);
276 32
        ExpectErr(tl, ')');
277 32
        vcc_NextToken(tl);
278
}
279
280
/*--------------------------------------------------------------------*/
281
282
static void
283 32940
parse_return(struct vcc *tl)
284
{
285
        unsigned hand;
286
        const char *h;
287
288 32940
        vcc_NextToken(tl);
289 32940
        AN(tl->curproc);
290 32940
        if (tl->t->tok == ';' && tl->curproc->method == NULL) {
291 2
                Fb(tl, 1, "return;\n");
292 2
                return;
293
        }
294 32938
        ExpectErr(tl, '(');
295 32936
        vcc_NextToken(tl);
296 32936
        ExpectErr(tl, ID);
297
298 32936
        hand = VCL_RET_MAX;
299 32936
        h = NULL;
300
#define VCL_RET_MAC(l, U, B)                            \
301
                if (vcc_IdIs(tl->t, #l)) {              \
302
                        hand = VCL_RET_ ## U;           \
303
                        h = #U;                         \
304
                }
305
#include "tbl/vcl_returns.h"
306 32936
        if (h == NULL) {
307 2
                VSB_printf(tl->sb, "Expected return action name.\n");
308 2
                vcc_ErrWhere(tl, tl->t);
309 2
                ERRCHK(tl);
310
        }
311 32934
        assert(hand < VCL_RET_MAX);
312
313 32934
        vcc_ProcAction(tl->curproc, hand, tl->t);
314 32934
        vcc_NextToken(tl);
315 32934
        if (tl->t->tok == '(') {
316 3298
                if (hand == VCL_RET_SYNTH)
317 3256
                        parse_return_synth(tl);
318 42
                else if (hand == VCL_RET_VCL)
319 32
                        parse_return_vcl(tl);
320 10
                else if (hand == VCL_RET_PASS)
321 8
                        parse_return_pass(tl);
322
                else {
323 2
                        VSB_printf(tl->sb, "Arguments not allowed.\n");
324 2
                        vcc_ErrWhere(tl, tl->t);
325
                }
326
        } else {
327 29636
                if (hand == VCL_RET_SYNTH || hand == VCL_RET_VCL) {
328 2
                        VSB_printf(tl->sb, "Missing argument.\n");
329 2
                        vcc_ErrWhere(tl, tl->t);
330
                }
331
        }
332 32934
        ERRCHK(tl);
333 32930
        Fb(tl, 1, "VRT_handling(ctx, VCL_RET_%s);\n", h);
334 32930
        ExpectErr(tl, ')');
335 32930
        vcc_NextToken(tl);
336
}
337
338
/*--------------------------------------------------------------------*/
339
340
static void
341 18
parse_synthetic(struct vcc *tl)
342
{
343 18
        vcc_NextToken(tl);
344
345 18
        ExpectErr(tl, '(');
346 18
        ERRCHK(tl);
347 18
        vcc_NextToken(tl);
348
349 18
        Fb(tl, 1, "VRT_synth_page(ctx, ");
350 18
        vcc_Expr(tl, STRING_LIST);
351 18
        ERRCHK(tl);
352 16
        Fb(tl, 1, ");\n");
353
354 16
        ExpectErr(tl, ')');
355 16
        vcc_NextToken(tl);
356 16
        ERRCHK(tl);
357
}
358
359
/*--------------------------------------------------------------------*/
360
361
typedef void action_f(struct vcc *tl);
362
363
static struct action_table {
364
        const char              *name;
365
        action_f                *func;
366
        unsigned                bitmask;
367
} action_table[] = {
368
        /* Keep list sorted from here */
369
        { "ban",                parse_ban },
370
        { "call",               parse_call },
371
        { "hash_data",          parse_hash_data, VCL_MET_HASH },
372
        { "new",                vcc_ParseNew, VCL_MET_INIT},
373
        { "return",             parse_return },
374
        { "set",                parse_set },
375
        { "synthetic",          parse_synthetic,
376
                VCL_MET_SYNTH | VCL_MET_BACKEND_ERROR },
377
        { "unset",              parse_unset },
378
        { NULL,                 NULL }
379
};
380
381
int
382 55818
vcc_ParseAction(struct vcc *tl)
383
{
384
        struct token *at;
385
        struct action_table *atp;
386
        const struct symbol *sym;
387
388 55818
        at = tl->t;
389 55818
        assert(at->tok == ID);
390 292734
        for (atp = action_table; atp->name != NULL; atp++) {
391 292010
                if (vcc_IdIs(at, atp->name)) {
392 55094
                        if (atp->bitmask != 0)
393 4892
                                vcc_AddUses(tl, at, atp->bitmask,
394
                                    "not a valid action");
395 55094
                        atp->func(tl);
396 55094
                        return (1);
397
                }
398
        }
399 724
        sym = VCC_SymbolTok(tl, NULL, tl->t, SYM_NONE, 0);
400 724
        if (sym != NULL && sym->kind == SYM_FUNC) {
401 714
                vcc_Expr_Call(tl, sym);
402 714
                return (1);
403
        }
404 10
        return (0);
405
}