vinyl-cache/bin/vinyld/cache/cache_vrt_filter.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2016 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 *
30
 */
31
32
#include "config.h"
33
34
#include <stdio.h>
35
#include <stdint.h>
36
#include <stdlib.h>
37
38
#include "cache_int.h"
39
#include "cache_vcl.h"
40
#include "vrt_obj.h"
41
42
#include "vct.h"
43
44
#include "cache_filter.h"
45
46
/*--------------------------------------------------------------------
47
 */
48
49
struct vfilter {
50
        unsigned                        magic;
51
#define VFILTER_MAGIC                   0xd40894e9
52
        const struct vfp                *vfp;
53
        const struct vdp                *vdp;
54
        const char                      *name;
55
        int                             nlen;
56
        VTAILQ_ENTRY(vfilter)           list;
57
};
58
59
static struct vfilter_head vrt_filters =
60
    VTAILQ_HEAD_INITIALIZER(vrt_filters);
61
62
static const char *
63 214186
is_dup_filter(const struct vfilter_head *head, const struct vfp * vfp,
64
    const struct vdp *vdp, const char *name)
65
{
66
        struct vfilter *vp;
67 1093239
        VTAILQ_FOREACH(vp, head, list) {
68 879074
                if (vfp != NULL && vp->vfp != NULL) {
69 234899
                        if (vp->vfp == vfp)
70 21
                                return ("VFP already registered");
71 234878
                        if (!strcasecmp(vp->name, name))
72 0
                                return ("VFP name already used");
73 234878
                }
74 879053
                if (vdp != NULL && vp->vdp != NULL) {
75 239148
                        if (vp->vdp == vdp)
76 0
                                return ("VDP already registered");
77 239148
                        if (!strcasecmp(vp->name, name))
78 0
                                return ("VDP name already used");
79 239148
                }
80 879053
        }
81 214165
        return (NULL);
82 214186
}
83
84
static const char *
85 190645
vrt_addfilter(VRT_CTX, const struct vfp *vfp, const struct vdp *vdp)
86
{
87
        struct vfilter *vp;
88 190645
        struct vfilter_head *hd = &vrt_filters;
89 190645
        const char *err, *name = NULL;
90
91 190645
        CHECK_OBJ_ORNULL(ctx, VRT_CTX_MAGIC);
92 190645
        assert(vfp != NULL || vdp != NULL);
93 190645
        assert(vfp == NULL || vfp->name != NULL);
94 190645
        assert(vdp == NULL || vdp->name != NULL);
95 190645
        assert(vfp == NULL || vdp == NULL || !strcasecmp(vfp->name, vdp->name));
96 190645
        if (vfp != NULL)
97 109165
                name = vfp->name;
98 81480
        else if (vdp != NULL)
99 81480
                name = vdp->name;
100 190645
        AN(name);
101
102 190645
        err = is_dup_filter(hd, vfp, vdp, name);
103 190645
        if (err != NULL) {
104 0
                if (ctx != NULL)
105 0
                        VRT_fail(ctx, "%s: %s (global)", name, err);
106 0
                return (err);
107
        }
108 190645
        if (ctx != NULL) {
109 23541
                ASSERT_CLI();
110 23541
                CHECK_OBJ_NOTNULL(ctx->vcl, VCL_MAGIC);
111 23541
                hd = &ctx->vcl->filters;
112 23541
                err = is_dup_filter(hd, vfp, vdp, name);
113 23541
                if (err != NULL) {
114 21
                        VRT_fail(ctx, "%s: %s (per-vcl)", name, err);
115 21
                        return (err);
116
                }
117 23520
        }
118
119 190624
        ALLOC_OBJ(vp, VFILTER_MAGIC);
120 190624
        AN(vp);
121 190624
        vp->vfp = vfp;
122 190624
        vp->vdp = vdp;
123 190624
        vp->name = name;
124 190624
        vp->nlen = vstrlen(name);
125 190624
        VTAILQ_INSERT_TAIL(hd, vp, list);
126 190624
        return (err);
127 190645
}
128
129
const char *
130 23541
VRT_AddFilter(VRT_CTX, const struct vfp *vfp, const struct vdp *vdp)
131
{
132
133 23541
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
134 23541
        return (vrt_addfilter(ctx, vfp, vdp));
135
}
136
137
void
138 4830
VRT_RemoveFilter(VRT_CTX, const struct vfp *vfp, const struct vdp *vdp)
139
{
140
        struct vfilter *vp;
141
        struct vfilter_head *hd;
142
143 4830
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
144 4830
        CHECK_OBJ_NOTNULL(ctx->vcl, VCL_MAGIC);
145 4830
        hd = &ctx->vcl->filters;
146 4830
        assert(vfp != NULL || vdp != NULL);
147 4830
        assert(vfp == NULL || vfp->name != NULL);
148 4830
        assert(vdp == NULL || vdp->name != NULL);
149 4830
        assert(vfp == NULL || vdp == NULL || !strcasecmp(vfp->name, vdp->name));
150
151 4830
        ASSERT_CLI();
152 4830
        VTAILQ_FOREACH(vp, hd, list) {
153 4830
                CHECK_OBJ_NOTNULL(vp, VFILTER_MAGIC);
154 4830
                if (vp->vfp == vfp && vp->vdp == vdp)
155 4830
                        break;
156 0
        }
157 4830
        AN(vp);
158 4830
        assert(vfp == NULL || !strcasecmp(vfp->name, vp->name));
159 4830
        assert(vdp == NULL || !strcasecmp(vdp->name, vp->name));
160 4830
        VTAILQ_REMOVE(hd, vp, list);
161 4830
        FREE_OBJ(vp);
162 4830
}
163
164
static const struct vfilter vfilter_error[1] = {{0}};
165
166
static const struct vfilter *
167 151304
vcl_filter_list_iter(int want_vfp, const struct vfilter_head *h1,
168
    const struct vfilter_head *h2, const char **flp)
169
{
170
        const char *fl, *q;
171
        const struct vfilter *vp;
172
173 151304
        AN(h1);
174 151304
        AN(h2);
175 151304
        AN(flp);
176
177 151304
        fl = *flp;
178 151304
        AN(fl);
179
180 175728
        while (vct_isspace(*fl))
181 24424
                fl++;
182 151304
        if (*fl == '\0') {
183 125746
                *flp = NULL;
184 125746
                return (NULL);
185
        }
186 214685
        for (q = fl; *q && !vct_isspace(*q); q++)
187 189127
                continue;
188 25558
        *flp = q;
189 154723
        VTAILQ_FOREACH(vp, h1, list) {
190 147100
                if (want_vfp && vp->vfp == NULL)
191 882
                        continue;
192 146218
                else if (!want_vfp && vp->vdp == NULL)
193 75595
                        continue;
194 70623
                if (vp->nlen == q - fl && !vmemcmp(fl, vp->name, vp->nlen))
195 17935
                        return (vp);
196 52688
        }
197 25200
        VTAILQ_FOREACH(vp, h2, list) {
198 25137
                if (want_vfp && vp->vfp == NULL)
199 336
                        continue;
200 24801
                else if (!want_vfp && vp->vdp == NULL)
201 0
                        continue;
202 24801
                if (vp->nlen == q - fl && !vmemcmp(fl, vp->name, vp->nlen))
203 7560
                        return (vp);
204 17241
        }
205 63
        *flp = fl;
206 63
        return (vfilter_error);
207 151304
}
208
209
int
210 43973
VCL_StackVFP(struct vfp_ctx *vc, const struct vcl *vcl, const char *fl)
211
{
212
        const struct vfilter *vp;
213
214 43973
        AN(fl);
215 43973
        VSLbs(vc->wrk->vsl, SLT_Filters, TOSTRAND(fl));
216
217 53906
        while (1) {
218 53906
                vp = vcl_filter_list_iter(1, &vrt_filters, &vcl->filters, &fl);
219 53906
                if (vp == NULL)
220 43469
                        return (0);
221 10437
                if (vp == vfilter_error)
222 42
                        return (VFP_Error(vc, "Filter '...%s' not found", fl));
223 10395
                if (VFP_Push(vc, vp->vfp) == NULL)
224 462
                        return (-1);
225
        }
226 43973
}
227
228
int
229 83639
VCL_StackVDP(struct vdp_ctx *vdc, const struct vcl *vcl, const char *fl,
230
    struct req *req, struct busyobj *bo)
231
{
232
        const struct vfilter *vp;
233
        struct vrt_ctx ctx[1];
234
235 83639
        CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC);
236 83639
        AN(vcl);
237 83639
        AN(fl);
238
239 83639
        CHECK_OBJ_ORNULL(req, REQ_MAGIC);
240 83639
        CHECK_OBJ_ORNULL(bo, BUSYOBJ_MAGIC);
241
242 83639
        assert((req ? 1 : 0) ^ (bo ? 1 : 0));
243
244 83639
        VSLbs(vdc->vsl, SLT_Filters, TOSTRAND(fl));
245 83639
        INIT_OBJ(ctx, VRT_CTX_MAGIC);
246
247 83639
        if (req)
248 83261
                VCL_Req2Ctx(ctx, req);
249
        else
250 378
                VCL_Bo2Ctx(ctx, bo);
251
252 97395
        while (1) {
253 97395
                vp = vcl_filter_list_iter(0, &vrt_filters, &vcl->filters, &fl);
254 97395
                if (vp == NULL)
255 82274
                        return (0);
256 15121
                if (vp == vfilter_error) {
257 42
                        VSLb(ctx->vsl, SLT_Error,
258 21
                            "Filter '...%s' not found", fl);
259 21
                        return (-1);
260
                }
261 15100
                if (VDP_Push(ctx, vdc, ctx->ws, vp->vdp, NULL))
262 1344
                        return (-1);
263
        }
264 83639
}
265
266
void
267 20888
VCL_VRT_Init(void)
268
{
269 20888
        AZ(vrt_addfilter(NULL, &VFP_testgunzip, NULL));
270 20888
        AZ(vrt_addfilter(NULL, &VFP_gunzip, NULL));
271 20888
        AZ(vrt_addfilter(NULL, &VFP_gzip, NULL));
272 20888
        AZ(vrt_addfilter(NULL, &VFP_esi, NULL));
273 20888
        AZ(vrt_addfilter(NULL, &VFP_esi_gzip, NULL));
274 20888
        AZ(vrt_addfilter(NULL, NULL, &VDP_esi));
275 20888
        AZ(vrt_addfilter(NULL, NULL, &VDP_gunzip));
276 20888
        AZ(vrt_addfilter(NULL, NULL, &VDP_range));
277 20888
}
278
279
/*--------------------------------------------------------------------
280
 */
281
282
typedef void filter_list_t(void *, struct vsb *vsb);
283
284
static const char *
285 110719
filter_on_ws(struct ws *ws, filter_list_t *func, void *arg)
286
{
287
        struct vsb vsb[1];
288
        const char *p;
289
290 110719
        AN(func);
291 110719
        AN(arg);
292 110719
        WS_VSB_new(vsb, ws);
293 110719
        func(arg, vsb);
294 110719
        p = WS_VSB_finish(vsb, ws, NULL);
295 110719
        if (p == NULL)
296 483
                p = "";
297 110719
        return (p);
298
}
299
300
/*--------------------------------------------------------------------
301
 */
302
303
static void v_matchproto_(filter_list_t)
304 26628
vbf_default_filter_list(void *arg, struct vsb *vsb)
305
{
306
        const struct busyobj *bo;
307
        const char *p;
308 26628
        int do_gzip, do_gunzip, is_gzip = 0, is_gunzip = 0;
309
310 26628
        CAST_OBJ_NOTNULL(bo, arg, BUSYOBJ_MAGIC);
311
312 26628
        do_gzip = bo->do_gzip;
313 26628
        do_gunzip = bo->do_gunzip;
314
315
        /*
316
         * The VCL variables beresp.do_g[un]zip tells us how we want the
317
         * object processed before it is stored.
318
         *
319
         * The backend Content-Encoding header tells us what we are going
320
         * to receive, which we classify in the following three classes:
321
         *
322
         *      "Content-Encoding: gzip"        --> object is gzipped.
323
         *      no Content-Encoding             --> object is not gzipped.
324
         *      anything else                   --> do nothing wrt gzip
325
         */
326
327
        /* No body -> done */
328 26628
        if (bo->htc->body_status == BS_NONE || bo->htc->content_length == 0)
329 0
                return;
330
331 26628
        if (!cache_param->http_gzip_support)
332 84
                do_gzip = do_gunzip = 0;
333
334 26628
        if (http_GetHdr(bo->beresp, H_Content_Encoding, &p))
335 4221
                is_gzip = !strcasecmp(p, "gzip");
336
        else
337 22407
                is_gunzip = 1;
338
339
        /* We won't gunzip unless it is gzipped */
340 26628
        if (do_gunzip && !is_gzip)
341 42
                do_gunzip = 0;
342
343
        /* We wont gzip unless if it already is gzipped */
344 26628
        if (do_gzip && !is_gunzip)
345 0
                do_gzip = 0;
346
347 26628
        if (do_gunzip || (is_gzip && bo->do_esi))
348 3339
                VSB_cat(vsb, " gunzip");
349
350 26628
        if (bo->do_esi && (do_gzip || (is_gzip && !do_gunzip))) {
351 3402
                VSB_cat(vsb, " esi_gzip");
352 3402
                return;
353
        }
354
355 23226
        if (bo->do_esi) {
356 3234
                VSB_cat(vsb, " esi");
357 3234
                return;
358
        }
359
360 19992
        if (do_gzip)
361 336
                VSB_cat(vsb, " gzip");
362
363 19992
        if (is_gzip && !do_gunzip)
364 882
                VSB_cat(vsb, " testgunzip");
365 26628
}
366
367
const char *
368 26627
VBF_Get_Filter_List(struct busyobj *bo)
369
{
370
371 26627
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
372 26627
        return (filter_on_ws(bo->ws, vbf_default_filter_list, bo));
373
}
374
375
static const char *
376 21
bereq_Empty_Filter(struct busyobj *bo)
377
{
378
379 21
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
380 21
        return ("");
381
}
382
383
/*--------------------------------------------------------------------
384
 */
385
386
static void v_matchproto_(filter_list_t)
387 84092
resp_default_filter_list(void *arg, struct vsb *vsb)
388
{
389
        struct req *req;
390
391 84092
        CAST_OBJ_NOTNULL(req, arg, REQ_MAGIC);
392
393 84092
        if (!req->disable_esi && req->objcore != NULL &&
394 83819
            ObjHasAttr(req->wrk, req->objcore, OA_ESIDATA))
395 4852
                VSB_cat(vsb, " esi");
396
397 90874
        if (cache_param->http_gzip_support &&
398 83926
            req->objcore != NULL &&
399 83926
            ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED) &&
400 6782
            !RFC2616_Req_Gzip(req->http))
401 2478
                VSB_cat(vsb, " gunzip");
402
403 155588
        if (cache_param->http_range_support &&
404 84015
            http_GetStatus(req->resp) == 200 &&
405 71496
            http_GetHdr(req->http, H_Range, NULL))
406 1239
                VSB_cat(vsb, " range");
407 84092
}
408
409
const char *
410 84095
resp_Get_Filter_List(struct req *req)
411
{
412
413 84095
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
414 84095
        return (filter_on_ws(req->ws, resp_default_filter_list, req));
415
}
416
417
static const char *
418 42
req_Empty_Filter(struct req *req)
419
{
420
421 42
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
422 42
        return ("");
423
}
424
425
/*--------------------------------------------------------------------
426
 * control if "set req.filters" is allowed
427
 *
428
 * req.body (conversely to other body object) is one where VCL has control over
429
 * when it gets processed by means of std.cache_req_body(): Filters act on the
430
 * received body when that function is called, so confusion could be caused if
431
 * people expect filters to have an effect when set/changed after the req.body
432
 * is already cached.
433
 */
434
435
static int
436 210
req_filter_can(struct req *req)
437
{
438
439 210
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
440 210
        return (req->req_body_status->avail == 1);
441
}
442
443
/*--------------------------------------------------------------------*/
444
445
//lint -emacro(506, FILTER_VAR) constant value boolean
446
//lint -emacro(774, FILTER_VAR) if always evaluates to false
447
#define FILTER_VAR(vcl, in, func, cond, fld)                            \
448
        VCL_STRING                                                      \
449
        VRT_r_##vcl##_filters(VRT_CTX)                                  \
450
        {                                                               \
451
                                                                        \
452
                CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);                  \
453
                if (ctx->in->fld != NULL)                               \
454
                        return(ctx->in->fld);                           \
455
                return (func(ctx->in));                                 \
456
        }                                                               \
457
                                                                        \
458
        VCL_VOID                                                        \
459
        VRT_l_##vcl##_filters(VRT_CTX, const char *str, VCL_STRANDS s)  \
460
        {                                                               \
461
                const char *b;                                          \
462
                                                                        \
463
                (void)str;                                              \
464
                CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);                  \
465
                if (! (cond)) {                                         \
466
                        VRT_fail(ctx, #vcl ".filters not settable");    \
467
                        return;                                         \
468
                }                                                       \
469
                b = VRT_StrandsWS(ctx->in->ws, str, s);                 \
470
                if (b == NULL)                                          \
471
                        WS_MarkOverflow(ctx->in->ws);                   \
472
                else                                                    \
473
                        ctx->in->fld = b;                               \
474
        }
475
476 1155
FILTER_VAR(bereq, bo, bereq_Empty_Filter, 1, vdp_filter_list)
477 882
FILTER_VAR(beresp, bo, VBF_Get_Filter_List, 1, vfp_filter_list)
478 252
FILTER_VAR(req, req, req_Empty_Filter, req_filter_can(ctx->req), vfp_filter_list)
479 13544
FILTER_VAR(resp, req, resp_Get_Filter_List, 1, vdp_filter_list)