varnish-cache/lib/libvmod_std/vmod_std.c
1
/*-
2
 * Copyright (c) 2010-2017 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@FreeBSD.org>
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 */
28
29
#include "config.h"
30
31
#include <sys/stat.h>
32
33
#include <netinet/in.h>
34
35
#include <ctype.h>
36
#include <stdlib.h>
37
#include <string.h>
38
#include <syslog.h>
39
#include <sys/socket.h>
40
#include <fnmatch.h>
41
42
#include "cache/cache.h"
43
44
#include "vrnd.h"
45
#include "vtcp.h"
46
#include "vsa.h"
47
#include "vtim.h"
48
#include "vcl.h"
49
50
#include "vcc_if.h"
51
52
VCL_VOID v_matchproto_(td_std_set_ip_tos)
53 8
vmod_set_ip_tos(VRT_CTX, VCL_INT tos)
54
{
55
        struct suckaddr *sa;
56 8
        int itos = tos;
57
58 8
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
59 8
        AZ(SES_Get_local_addr(ctx->req->sp, &sa));
60
        /* Silently ignore for non-IP addresses. */
61 8
        if (VSA_Compare(sa, bogo_ip) == 0)
62 4
                return;
63 4
        VTCP_Assert(setsockopt(ctx->req->sp->fd,
64
            IPPROTO_IP, IP_TOS, &itos, sizeof(itos)));
65
}
66
67
static const char *
68 48
vmod_updown(VRT_CTX, int up, const char *s, va_list ap)
69
{
70
        unsigned u;
71
        char *b, *e;
72
        const char *p;
73
74 48
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
75 48
        u = WS_Reserve(ctx->ws, 0);
76 48
        e = b = ctx->ws->f;
77 48
        e += u;
78 48
        p = s;
79 144
        while (p != vrt_magic_string_end && b < e) {
80 48
                if (p != NULL) {
81 8776
                        for (; b < e && *p != '\0'; p++)
82 8728
                                if (up)
83 4328
                                        *b++ = (char)toupper(*p);
84
                                else
85 4400
                                        *b++ = (char)tolower(*p);
86
                }
87 48
                p = va_arg(ap, const char *);
88
        }
89 48
        if (b < e)
90 48
                *b = '\0';
91 48
        b++;
92 48
        if (b > e) {
93 0
                WS_MarkOverflow(ctx->ws);
94 0
                WS_Release(ctx->ws, 0);
95 0
                return (NULL);
96
        } else {
97 48
                e = b;
98 48
                b = ctx->ws->f;
99 48
                WS_Release(ctx->ws, e - b);
100 48
                return (b);
101
        }
102
}
103
104
VCL_STRING v_matchproto_(td_std_toupper)
105 16
vmod_toupper(VRT_CTX, const char *s, ...)
106
{
107
        const char *p;
108
        va_list ap;
109
110 16
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
111 16
        va_start(ap, s);
112 16
        p = vmod_updown(ctx, 1, s, ap);
113 16
        va_end(ap);
114 16
        return (p);
115
}
116
117
VCL_STRING v_matchproto_(td_std_tolower)
118 32
vmod_tolower(VRT_CTX, const char *s, ...)
119
{
120
        const char *p;
121
        va_list ap;
122
123 32
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
124 32
        va_start(ap, s);
125 32
        p = vmod_updown(ctx, 0, s, ap);
126 32
        va_end(ap);
127 32
        return (p);
128
}
129
130
VCL_REAL v_matchproto_(td_std_random)
131 304
vmod_random(VRT_CTX, VCL_REAL lo, VCL_REAL hi)
132
{
133
        double a;
134
135 304
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
136 304
        a = VRND_RandomTestableDouble();
137 304
        a *= hi - lo;
138 304
        a += lo;
139 304
        return (a);
140
}
141
142
VCL_VOID v_matchproto_(td_std_log)
143 236
vmod_log(VRT_CTX, const char *fmt, ...)
144
{
145
        const char *p;
146
        va_list ap;
147
        uintptr_t sn;
148
149 236
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
150 236
        sn = WS_Snapshot(ctx->ws);
151 236
        va_start(ap, fmt);
152 236
        p = VRT_String(ctx->ws, NULL, fmt, ap);
153 236
        va_end(ap);
154
155 236
        if (p == NULL) {
156 0
                WS_Reset(ctx->ws, sn);
157 0
                WS_MarkOverflow(ctx->ws);
158 0
                return;
159
        }
160
161 236
        AN(p);
162 236
        if (ctx->vsl != NULL)
163 112
                VSLb(ctx->vsl, SLT_VCL_Log, "%s", p);
164
        else
165 124
                VSL(SLT_VCL_Log, 0, "%s", p);
166 236
        WS_Reset(ctx->ws, sn);
167
}
168
169
/* XXX use vsyslog() ? */
170
VCL_VOID v_matchproto_(td_std_syslog)
171 12
vmod_syslog(VRT_CTX, VCL_INT fac, const char *fmt, ...)
172
{
173
        const char *p;
174
        va_list ap;
175
        uintptr_t sn;
176
177 12
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
178 12
        sn = WS_Snapshot(ctx->ws);
179 12
        va_start(ap, fmt);
180 12
        p = VRT_String(ctx->ws, NULL, fmt, ap);
181 12
        va_end(ap);
182 12
        if (p != NULL)
183 12
                syslog((int)fac, "%s", p);
184 12
        WS_Reset(ctx->ws, sn);
185 12
}
186
187
VCL_BOOL v_matchproto_(td_std_file_exists)
188 8
vmod_file_exists(VRT_CTX, VCL_STRING file_name)
189
{
190
        struct stat st;
191
192 8
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
193 8
        return (stat(file_name, &st) == 0);
194
}
195
196
VCL_VOID v_matchproto_(td_std_collect)
197 40
vmod_collect(VRT_CTX, VCL_HEADER hdr, VCL_STRING sep)
198
{
199
        struct http *hp;
200
201 40
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
202 40
        hp = VRT_selecthttp(ctx, hdr->where);
203 40
        http_CollectHdrSep(hp, hdr->what, sep);
204 40
}
205
206
VCL_BOOL v_matchproto_(td_std_healthy)
207 104
vmod_healthy(VRT_CTX, VCL_BACKEND be)
208
{
209 104
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
210 104
        CHECK_OBJ_ORNULL(be, DIRECTOR_MAGIC);
211 104
        return (VRT_Healthy(ctx, be, NULL));
212
}
213
214
VCL_INT v_matchproto_(td_std_port)
215 240
vmod_port(VRT_CTX, VCL_IP ip)
216
{
217 240
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
218 240
        if (ip == NULL)
219 0
                return (0);
220 240
        return (VSA_Port(ip));
221
}
222
223
VCL_VOID v_matchproto_(td_std_rollback)
224 16
vmod_rollback(VRT_CTX, VCL_HTTP hp)
225
{
226 16
        VRT_Rollback(ctx, hp);
227 16
}
228
229
VCL_VOID v_matchproto_(td_std_timestamp)
230 24
vmod_timestamp(VRT_CTX, VCL_STRING label)
231
{
232
233 24
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
234 24
        if (label == NULL)
235 0
                return;
236 24
        if (*label == '\0')
237 0
                return;
238 24
        if (ctx->bo != NULL && ctx->req == NULL) {
239
                /* Called from backend vcl methods */
240 4
                CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
241 4
                VSLb_ts_busyobj(ctx->bo, label, VTIM_real());
242 20
        } else if (ctx->req != NULL) {
243
                /* Called from request vcl methods */
244 16
                CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
245 16
                VSLb_ts_req(ctx->req, label, VTIM_real());
246
        }
247
}
248
249
VCL_BOOL v_matchproto_(td_std_cache_req_body)
250 44
vmod_cache_req_body(VRT_CTX, VCL_BYTES size)
251
{
252 44
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
253 44
        if (size < 0)
254 0
                size = 0;
255 44
        if (VRT_CacheReqBody(ctx, (size_t)size) < 0)
256 12
                return (0);
257 32
        return (1);
258
}
259
260
VCL_STRING v_matchproto_(td_std_strstr)
261 12
vmod_strstr(VRT_CTX, VCL_STRING s1, VCL_STRING s2)
262
{
263 12
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
264 12
        if (s1 == NULL || s2 == NULL)
265 4
                return (NULL);
266 8
        return (strstr(s1, s2));
267
}
268
269
VCL_STRING v_matchproto_(td_std_getenv)
270 20
vmod_getenv(VRT_CTX, VCL_STRING name)
271
{
272 20
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
273 20
        if (name == NULL || *name == '\0')
274 4
                return (NULL);
275 16
        return (getenv(name));
276
}
277
278
VCL_VOID v_matchproto_(td_std_late_100_continue)
279 20
vmod_late_100_continue(VRT_CTX, VCL_BOOL late)
280
{
281 20
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
282 20
        if (ctx->method != VCL_MET_RECV) {
283 0
                VSLb(ctx->vsl, SLT_VCL_Error,
284
                    "std.late_100_continue() only valid in vcl_recv{}");
285 0
                return;
286
        }
287
288 20
        CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
289 20
        if (ctx->req->want100cont)
290 20
                ctx->req->late100cont = late;
291
}
292
293
VCL_BOOL v_matchproto_(td_std_syntax)
294 24
vmod_syntax(VRT_CTX, VCL_REAL r)
295
{
296
297 24
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
298 24
        assert(ctx->syntax == 40 || ctx->syntax == 41);
299
        /*
300
         * We need to be careful because non-integer numbers have imprecise
301
         * IEE754 representation (4.1 is 0x1.0666666666666p+2 = 4.09999...)
302
         * By scaling up and rounding, this is taken care of.
303
         */
304 24
        return (round(r * 10) <= ctx->syntax);
305
}
306
307
VCL_BOOL v_matchproto_(td_std_fnmatch)
308 248
vmod_fnmatch(VRT_CTX, VCL_STRING pattern, VCL_STRING subject,
309
             VCL_BOOL pathname, VCL_BOOL noescape, VCL_BOOL period)
310
{
311 248
        int flags = 0;
312
313 248
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
314 248
        if (pattern == NULL) {
315 4
                VRT_fail(ctx, "std.fnmatch(): pattern is NULL");
316 4
                return (0);
317
        }
318 244
        if (subject == NULL) {
319 4
                VRT_fail(ctx, "std.fnmatch(): subject is NULL");
320 4
                return (0);
321
        }
322
323 240
        if (pathname)
324 180
                flags |= FNM_PATHNAME;
325 240
        if (noescape)
326 60
                flags |= FNM_NOESCAPE;
327 240
        if (period)
328 60
                flags |= FNM_PERIOD;
329 240
        return (fnmatch(pattern, subject, flags) != FNM_NOMATCH);
330
}