varnish-cache/bin/varnishd/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_varnishd.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 187226
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 849742
        VTAILQ_FOREACH(vp, head, list) {
68 662541
                if (vfp != NULL && vp->vfp != NULL) {
69 234120
                        if (vp->vfp == vfp)
70 25
                                return ("VFP already registered");
71 234095
                        if (!strcasecmp(vp->name, name))
72 0
                                return ("VFP name already used");
73 234095
                }
74 662516
                if (vdp != NULL && vp->vdp != NULL) {
75 83466
                        if (vp->vdp == vdp)
76 0
                                return ("VDP already registered");
77 83466
                        if (!strcasecmp(vp->name, name))
78 0
                                return ("VDP name already used");
79 83466
                }
80 662516
        }
81 187201
        return (NULL);
82 187226
}
83
84
static const char *
85 182401
vrt_addfilter(VRT_CTX, const struct vfp *vfp, const struct vdp *vdp)
86
{
87
        struct vfilter *vp;
88 182401
        struct vfilter_head *hd = &vrt_filters;
89 182401
        const char *err, *name = NULL;
90
91 182401
        CHECK_OBJ_ORNULL(ctx, VRT_CTX_MAGIC);
92 182401
        assert(vfp != NULL || vdp != NULL);
93 182401
        assert(vfp == NULL || vfp->name != NULL);
94 182401
        assert(vdp == NULL || vdp->name != NULL);
95 182401
        assert(vfp == NULL || vdp == NULL || !strcasecmp(vfp->name, vdp->name));
96 182401
        if (vfp != NULL)
97 113410
                name = vfp->name;
98 68991
        else if (vdp != NULL)
99 68991
                name = vdp->name;
100 182401
        AN(name);
101
102 182401
        err = is_dup_filter(hd, vfp, vdp, name);
103 182401
        if (err != NULL) {
104 0
                if (ctx != NULL)
105 0
                        VRT_fail(ctx, "%s: %s (global)", name, err);
106 0
                return (err);
107
        }
108 182401
        if (ctx != NULL) {
109 4825
                ASSERT_CLI();
110 4825
                CHECK_OBJ_NOTNULL(ctx->vcl, VCL_MAGIC);
111 4825
                hd = &ctx->vcl->filters;
112 4825
                err = is_dup_filter(hd, vfp, vdp, name);
113 4825
                if (err != NULL) {
114 25
                        VRT_fail(ctx, "%s: %s (per-vcl)", name, err);
115 25
                        return (err);
116
                }
117 4800
        }
118
119 182376
        ALLOC_OBJ(vp, VFILTER_MAGIC);
120 182376
        AN(vp);
121 182376
        vp->vfp = vfp;
122 182376
        vp->vdp = vdp;
123 182376
        vp->name = name;
124 182376
        vp->nlen = strlen(name);
125 182376
        VTAILQ_INSERT_TAIL(hd, vp, list);
126 182376
        return (err);
127 182401
}
128
129
const char *
130 4825
VRT_AddFilter(VRT_CTX, const struct vfp *vfp, const struct vdp *vdp)
131
{
132
133 4825
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
134 4825
        return (vrt_addfilter(ctx, vfp, vdp));
135
}
136
137
void
138 0
VRT_AddVFP(VRT_CTX, const struct vfp *filter)
139
{
140 0
        AZ(VRT_AddFilter(ctx, filter, NULL));
141 0
}
142
143
void
144 0
VRT_AddVDP(VRT_CTX, const struct vdp *filter)
145
{
146 0
        AZ(VRT_AddFilter(ctx, NULL, filter));
147 0
}
148
149
void
150 1150
VRT_RemoveFilter(VRT_CTX, const struct vfp *vfp, const struct vdp *vdp)
151
{
152
        struct vfilter *vp;
153
        struct vfilter_head *hd;
154
155 1150
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
156 1150
        CHECK_OBJ_NOTNULL(ctx->vcl, VCL_MAGIC);
157 1150
        hd = &ctx->vcl->filters;
158 1150
        assert(vfp != NULL || vdp != NULL);
159 1150
        assert(vfp == NULL || vfp->name != NULL);
160 1150
        assert(vdp == NULL || vdp->name != NULL);
161 1150
        assert(vfp == NULL || vdp == NULL || !strcasecmp(vfp->name, vdp->name));
162
163 1150
        ASSERT_CLI();
164 1150
        VTAILQ_FOREACH(vp, hd, list) {
165 1150
                CHECK_OBJ_NOTNULL(vp, VFILTER_MAGIC);
166 1150
                if (vp->vfp == vfp && vp->vdp == vdp)
167 1150
                        break;
168 0
        }
169 1150
        AN(vp);
170 1150
        assert(vfp == NULL || !strcasecmp(vfp->name, vp->name));
171 1150
        assert(vdp == NULL || !strcasecmp(vdp->name, vp->name));
172 1150
        VTAILQ_REMOVE(hd, vp, list);
173 1150
        FREE_OBJ(vp);
174 1150
}
175
176
void
177 0
VRT_RemoveVFP(VRT_CTX, const struct vfp *filter)
178
{
179
180 0
        VRT_RemoveFilter(ctx, filter, NULL);
181 0
}
182
183
void
184 0
VRT_RemoveVDP(VRT_CTX, const struct vdp *filter)
185
{
186
187 0
        VRT_RemoveFilter(ctx, NULL, filter);
188 0
}
189
190
static const struct vfilter vfilter_error[1];
191
192
// XXX: idea(fgs): Allow filters (...) arguments in the list
193
static const struct vfilter *
194 153532
vcl_filter_list_iter(int want_vfp, const struct vfilter_head *h1,
195
    const struct vfilter_head *h2, const char **flp)
196
{
197
        const char *fl, *q;
198
        const struct vfilter *vp;
199
200 153532
        AN(h1);
201 153532
        AN(h2);
202 153532
        AN(flp);
203
204 153532
        fl = *flp;
205 153532
        AN(fl);
206
207 180004
        while (vct_isspace(*fl))
208 26472
                fl++;
209 153532
        if (*fl == '\0') {
210 126808
                *flp = NULL;
211 126808
                return (NULL);
212
        }
213 218011
        for (q = fl; *q && !vct_isspace(*q); q++)
214 191287
                continue;
215 26724
        *flp = q;
216 153912
        VTAILQ_FOREACH(vp, h1, list) {
217 147438
                if (want_vfp && vp->vfp == NULL)
218 375
                        continue;
219 147063
                else if (!want_vfp && vp->vdp == NULL)
220 73616
                        continue;
221 73447
                if (vp->nlen == q - fl && !memcmp(fl, vp->name, vp->nlen))
222 20250
                        return (vp);
223 53197
        }
224 12723
        VTAILQ_FOREACH(vp, h2, list) {
225 12673
                if (want_vfp && vp->vfp == NULL)
226 50
                        continue;
227 12623
                else if (!want_vfp && vp->vdp == NULL)
228 0
                        continue;
229 12623
                if (vp->nlen == q - fl && !memcmp(fl, vp->name, vp->nlen))
230 6424
                        return (vp);
231 6199
        }
232 50
        *flp = fl;
233 50
        return (vfilter_error);
234 153532
}
235
236
int
237 46423
VCL_StackVFP(struct vfp_ctx *vc, const struct vcl *vcl, const char *fl)
238
{
239
        const struct vfilter *vp;
240
241 46423
        AN(fl);
242 46423
        VSLbs(vc->wrk->vsl, SLT_Filters, TOSTRAND(fl));
243
244 57823
        while (1) {
245 57823
                vp = vcl_filter_list_iter(1, &vrt_filters, &vcl->filters, &fl);
246 57823
                if (vp == NULL)
247 45823
                        return (0);
248 12000
                if (vp == vfilter_error)
249 50
                        return (VFP_Error(vc, "Filter '...%s' not found", fl));
250 11950
                if (VFP_Push(vc, vp->vfp) == NULL)
251 550
                        return (-1);
252
        }
253 46423
}
254
255
int
256 84134
VCL_StackVDP(struct req *req, const struct vcl *vcl, const char *fl)
257
{
258
        const struct vfilter *vp;
259
        struct vrt_ctx ctx[1];
260
261 84134
        AN(fl);
262 84134
        VSLbs(req->vsl, SLT_Filters, TOSTRAND(fl));
263 84134
        INIT_OBJ(ctx, VRT_CTX_MAGIC);
264 84134
        VCL_Req2Ctx(ctx, req);
265
266 95709
        while (1) {
267 95709
                vp = vcl_filter_list_iter(0, &vrt_filters, &vcl->filters, &fl);
268 95709
                if (vp == NULL)
269 80984
                        return (0);
270 14725
                if (vp == vfilter_error) {
271 0
                        VSLb(req->vsl, SLT_Error,
272 0
                            "Filter '...%s' not found", fl);
273 0
                        return (-1);
274
                }
275 14725
                if (VDP_Push(ctx, req->vdc, req->ws, vp->vdp, NULL))
276 3150
                        return (-1);
277
        }
278 84134
}
279
280
void
281 22197
VCL_VRT_Init(void)
282
{
283 22197
        AZ(vrt_addfilter(NULL, &VFP_testgunzip, NULL));
284 22197
        AZ(vrt_addfilter(NULL, &VFP_gunzip, NULL));
285 22197
        AZ(vrt_addfilter(NULL, &VFP_gzip, NULL));
286 22197
        AZ(vrt_addfilter(NULL, &VFP_esi, NULL));
287 22197
        AZ(vrt_addfilter(NULL, &VFP_esi_gzip, NULL));
288 22197
        AZ(vrt_addfilter(NULL, NULL, &VDP_esi));
289 22197
        AZ(vrt_addfilter(NULL, NULL, &VDP_gunzip));
290 22197
        AZ(vrt_addfilter(NULL, NULL, &VDP_range));
291 22197
}
292
293
/*--------------------------------------------------------------------
294
 */
295
296
typedef void filter_list_t(void *, struct vsb *vsb);
297
298
static const char *
299 114522
filter_on_ws(struct ws *ws, filter_list_t *func, void *arg)
300
{
301
        struct vsb vsb[1];
302
        const char *p;
303
304 114522
        AN(func);
305 114522
        AN(arg);
306 114522
        WS_VSB_new(vsb, ws);
307 114522
        func(arg, vsb);
308 114522
        p = WS_VSB_finish(vsb, ws, NULL);
309 114522
        if (p == NULL)
310 575
                p = "";
311 114522
        return (p);
312
}
313
314
/*--------------------------------------------------------------------
315
 */
316
317
static void v_matchproto_(filter_list_t)
318 29525
vbf_default_filter_list(void *arg, struct vsb *vsb)
319
{
320
        const struct busyobj *bo;
321
        const char *p;
322 29525
        int do_gzip, do_gunzip, is_gzip = 0, is_gunzip = 0;
323
324 29525
        CAST_OBJ_NOTNULL(bo, arg, BUSYOBJ_MAGIC);
325
326 29525
        do_gzip = bo->do_gzip;
327 29525
        do_gunzip = bo->do_gunzip;
328
329
        /*
330
         * The VCL variables beresp.do_g[un]zip tells us how we want the
331
         * object processed before it is stored.
332
         *
333
         * The backend Content-Encoding header tells us what we are going
334
         * to receive, which we classify in the following three classes:
335
         *
336
         *      "Content-Encoding: gzip"        --> object is gzip'ed.
337
         *      no Content-Encoding             --> object is not gzip'ed.
338
         *      anything else                   --> do nothing wrt gzip
339
         */
340
341
        /* No body -> done */
342 29525
        if (bo->htc->body_status == BS_NONE || bo->htc->content_length == 0)
343 6
                return;
344
345 29523
        if (!cache_param->http_gzip_support)
346 100
                do_gzip = do_gunzip = 0;
347
348 29523
        if (http_GetHdr(bo->beresp, H_Content_Encoding, &p))
349 5000
                is_gzip = !strcasecmp(p, "gzip");
350
        else
351 24523
                is_gunzip = 1;
352
353
        /* We won't gunzip unless it is gzip'ed */
354 29523
        if (do_gunzip && !is_gzip)
355 50
                do_gunzip = 0;
356
357
        /* We wont gzip unless if it already is gzip'ed */
358 29523
        if (do_gzip && !is_gunzip)
359 0
                do_gzip = 0;
360
361 29523
        if (do_gunzip || (is_gzip && bo->do_esi))
362 3975
                VSB_cat(vsb, " gunzip");
363
364 29523
        if (bo->do_esi && (do_gzip || (is_gzip && !do_gunzip))) {
365 4050
                VSB_cat(vsb, " esi_gzip");
366 4050
                return;
367
        }
368
369 25473
        if (bo->do_esi) {
370 3675
                VSB_cat(vsb, " esi");
371 3675
                return;
372
        }
373
374 21798
        if (do_gzip)
375 400
                VSB_cat(vsb, " gzip");
376
377 21798
        if (is_gzip && !do_gunzip)
378 1025
                VSB_cat(vsb, " testgunzip");
379 29523
}
380
381
const char *
382 29522
VBF_Get_Filter_List(struct busyobj *bo)
383
{
384
385 29522
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
386 29522
        return (filter_on_ws(bo->ws, vbf_default_filter_list, bo));
387
}
388
389
/*--------------------------------------------------------------------
390
 */
391
392
static void v_matchproto_(filter_list_t)
393 85000
resp_default_filter_list(void *arg, struct vsb *vsb)
394
{
395
        struct req *req;
396
397 85000
        CAST_OBJ_NOTNULL(req, arg, REQ_MAGIC);
398
399 85000
        if (!req->disable_esi && req->objcore != NULL &&
400 84621
            ObjHasAttr(req->wrk, req->objcore, OA_ESIDATA))
401 5550
                VSB_cat(vsb, " esi");
402
403 91475
        if (cache_param->http_gzip_support &&
404 84795
            req->objcore != NULL &&
405 84745
            ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED) &&
406 6475
            !RFC2616_Req_Gzip(req->http))
407 2150
                VSB_cat(vsb, " gunzip");
408
409 155552
        if (cache_param->http_range_support &&
410 84904
            http_GetStatus(req->resp) == 200 &&
411 70552
            http_GetHdr(req->http, H_Range, NULL))
412 1425
                VSB_cat(vsb, " range");
413 85000
}
414
415
const char *
416 85003
resp_Get_Filter_List(struct req *req)
417
{
418 85003
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
419 85003
        return (filter_on_ws(req->ws, resp_default_filter_list, req));
420
}
421
422
/*--------------------------------------------------------------------*/
423
424
#define FILTER_VAR(vcl, in, func, fld)                                  \
425
        VCL_STRING                                                      \
426
        VRT_r_##vcl##_filters(VRT_CTX)                                  \
427
        {                                                               \
428
                                                                        \
429
                CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);                  \
430
                if (ctx->in->fld != NULL)                               \
431
                        return(ctx->in->fld);                           \
432
                return (func(ctx->in));                                 \
433
        }                                                               \
434
                                                                        \
435
        VCL_VOID                                                        \
436
        VRT_l_##vcl##_filters(VRT_CTX, const char *str, VCL_STRANDS s)  \
437
        {                                                               \
438
                const char *b;                                          \
439
                                                                        \
440
                (void)str;                                              \
441
                CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);                  \
442
                b = VRT_StrandsWS(ctx->in->ws, str, s);                 \
443
                if (b == NULL)                                          \
444
                        WS_MarkOverflow(ctx->in->ws);                   \
445
                else                                                    \
446
                        ctx->in->fld = b;                               \
447
        }
448
449 1050
FILTER_VAR(beresp, bo, VBF_Get_Filter_List, vfp_filter_list)
450 13549
FILTER_VAR(resp, req, resp_Get_Filter_List, vdp_filter_list)