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
41
#include "cache/cache.h"
42
43
#include "vrnd.h"
44
#include "vtcp.h"
45
#include "vsa.h"
46
#include "vtim.h"
47
#include "vcl.h"
48
49
#include "vcc_if.h"
50
51
VCL_VOID v_matchproto_(td_std_set_ip_tos)
52 6
vmod_set_ip_tos(VRT_CTX, VCL_INT tos)
53
{
54
        struct suckaddr *sa;
55 6
        int itos = tos;
56
57 6
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
58 6
        AZ(SES_Get_local_addr(ctx->req->sp, &sa));
59
        /* Silently ignore for non-IP addresses. */
60 6
        if (VSA_Compare(sa, bogo_ip) == 0)
61 3
                return;
62 3
        VTCP_Assert(setsockopt(ctx->req->sp->fd,
63
            IPPROTO_IP, IP_TOS, &itos, sizeof(itos)));
64
}
65
66
static const char *
67 36
vmod_updown(VRT_CTX, int up, const char *s, va_list ap)
68
{
69
        unsigned u;
70
        char *b, *e;
71
        const char *p;
72
73 36
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
74 36
        u = WS_Reserve(ctx->ws, 0);
75 36
        e = b = ctx->ws->f;
76 36
        e += u;
77 36
        p = s;
78 108
        while (p != vrt_magic_string_end && b < e) {
79 36
                if (p != NULL) {
80 6582
                        for (; b < e && *p != '\0'; p++)
81 6546
                                if (up)
82 3246
                                        *b++ = (char)toupper(*p);
83
                                else
84 3300
                                        *b++ = (char)tolower(*p);
85
                }
86 36
                p = va_arg(ap, const char *);
87
        }
88 36
        if (b < e)
89 36
                *b = '\0';
90 36
        b++;
91 36
        if (b > e) {
92 0
                WS_MarkOverflow(ctx->ws);
93 0
                WS_Release(ctx->ws, 0);
94 0
                return (NULL);
95
        } else {
96 36
                e = b;
97 36
                b = ctx->ws->f;
98 36
                WS_Release(ctx->ws, e - b);
99 36
                return (b);
100
        }
101
}
102
103
VCL_STRING v_matchproto_(td_std_toupper)
104 12
vmod_toupper(VRT_CTX, const char *s, ...)
105
{
106
        const char *p;
107
        va_list ap;
108
109 12
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
110 12
        va_start(ap, s);
111 12
        p = vmod_updown(ctx, 1, s, ap);
112 12
        va_end(ap);
113 12
        return (p);
114
}
115
116
VCL_STRING v_matchproto_(td_std_tolower)
117 24
vmod_tolower(VRT_CTX, const char *s, ...)
118
{
119
        const char *p;
120
        va_list ap;
121
122 24
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
123 24
        va_start(ap, s);
124 24
        p = vmod_updown(ctx, 0, s, ap);
125 24
        va_end(ap);
126 24
        return (p);
127
}
128
129
VCL_REAL v_matchproto_(td_std_random)
130 228
vmod_random(VRT_CTX, VCL_REAL lo, VCL_REAL hi)
131
{
132
        double a;
133
134 228
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
135 228
        a = VRND_RandomTestableDouble();
136 228
        a *= hi - lo;
137 228
        a += lo;
138 228
        return (a);
139
}
140
141
VCL_VOID v_matchproto_(td_std_log)
142 177
vmod_log(VRT_CTX, const char *fmt, ...)
143
{
144
        const char *p;
145
        va_list ap;
146
        uintptr_t sn;
147
148 177
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
149 177
        sn = WS_Snapshot(ctx->ws);
150 177
        va_start(ap, fmt);
151 177
        p = VRT_String(ctx->ws, NULL, fmt, ap);
152 177
        va_end(ap);
153
154 177
        if (p == NULL) {
155 0
                WS_Reset(ctx->ws, sn);
156 0
                WS_MarkOverflow(ctx->ws);
157 0
                return;
158
        }
159
160 177
        AN(p);
161 177
        if (ctx->vsl != NULL)
162 84
                VSLb(ctx->vsl, SLT_VCL_Log, "%s", p);
163
        else
164 93
                VSL(SLT_VCL_Log, 0, "%s", p);
165 177
        WS_Reset(ctx->ws, sn);
166
}
167
168
/* XXX use vsyslog() ? */
169
VCL_VOID v_matchproto_(td_std_syslog)
170 9
vmod_syslog(VRT_CTX, VCL_INT fac, const char *fmt, ...)
171
{
172
        const char *p;
173
        va_list ap;
174
        uintptr_t sn;
175
176 9
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
177 9
        sn = WS_Snapshot(ctx->ws);
178 9
        va_start(ap, fmt);
179 9
        p = VRT_String(ctx->ws, NULL, fmt, ap);
180 9
        va_end(ap);
181 9
        if (p != NULL)
182 9
                syslog((int)fac, "%s", p);
183 9
        WS_Reset(ctx->ws, sn);
184 9
}
185
186
VCL_BOOL v_matchproto_(td_std_file_exists)
187 6
vmod_file_exists(VRT_CTX, VCL_STRING file_name)
188
{
189
        struct stat st;
190
191 6
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
192 6
        return (stat(file_name, &st) == 0);
193
}
194
195
VCL_VOID v_matchproto_(td_std_collect)
196 30
vmod_collect(VRT_CTX, VCL_HEADER hdr, VCL_STRING sep)
197
{
198
        struct http *hp;
199
200 30
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
201 30
        hp = VRT_selecthttp(ctx, hdr->where);
202 30
        http_CollectHdrSep(hp, hdr->what, sep);
203 30
}
204
205
VCL_BOOL v_matchproto_(td_std_healthy)
206 78
vmod_healthy(VRT_CTX, VCL_BACKEND be)
207
{
208 78
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
209 78
        CHECK_OBJ_ORNULL(be, DIRECTOR_MAGIC);
210 78
        return (VRT_Healthy(ctx, be, NULL));
211
}
212
213
VCL_INT v_matchproto_(td_std_port)
214 180
vmod_port(VRT_CTX, VCL_IP ip)
215
{
216 180
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
217 180
        if (ip == NULL)
218 0
                return (0);
219 180
        return (VSA_Port(ip));
220
}
221
222
VCL_VOID v_matchproto_(td_std_rollback)
223 12
vmod_rollback(VRT_CTX, VCL_HTTP hp)
224
{
225 12
        VRT_Rollback(ctx, hp);
226 12
}
227
228
VCL_VOID v_matchproto_(td_std_timestamp)
229 18
vmod_timestamp(VRT_CTX, VCL_STRING label)
230
{
231
232 18
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
233 18
        if (label == NULL)
234 0
                return;
235 18
        if (*label == '\0')
236 0
                return;
237 18
        if (ctx->bo != NULL && ctx->req == NULL) {
238
                /* Called from backend vcl methods */
239 3
                CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
240 3
                VSLb_ts_busyobj(ctx->bo, label, VTIM_real());
241 15
        } else if (ctx->req != NULL) {
242
                /* Called from request vcl methods */
243 12
                CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
244 12
                VSLb_ts_req(ctx->req, label, VTIM_real());
245
        }
246
}
247
248
VCL_BOOL v_matchproto_(td_std_cache_req_body)
249 33
vmod_cache_req_body(VRT_CTX, VCL_BYTES size)
250
{
251 33
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
252 33
        if (size < 0)
253 0
                size = 0;
254 33
        if (VRT_CacheReqBody(ctx, (size_t)size) < 0)
255 9
                return (0);
256 24
        return (1);
257
}
258
259
VCL_STRING v_matchproto_(td_std_strstr)
260 9
vmod_strstr(VRT_CTX, VCL_STRING s1, VCL_STRING s2)
261
{
262 9
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
263 9
        if (s1 == NULL || s2 == NULL)
264 3
                return (NULL);
265 6
        return (strstr(s1, s2));
266
}
267
268
VCL_STRING v_matchproto_(td_std_getenv)
269 15
vmod_getenv(VRT_CTX, VCL_STRING name)
270
{
271 15
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
272 15
        if (name == NULL || *name == '\0')
273 3
                return (NULL);
274 12
        return (getenv(name));
275
}
276
277
VCL_VOID v_matchproto_(td_std_late_100_continue)
278 15
vmod_late_100_continue(VRT_CTX, VCL_BOOL late)
279
{
280 15
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
281 15
        if (ctx->method != VCL_MET_RECV) {
282 0
                VSLb(ctx->vsl, SLT_VCL_Error,
283
                    "std.late_100_continue() only valid in vcl_recv{}");
284 0
                return;
285
        }
286
287 15
        CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
288 15
        if (ctx->req->want100cont)
289 15
                ctx->req->late100cont = late;
290
}
291
292
VCL_BOOL v_matchproto_(td_std_syntax)
293 18
vmod_syntax(VRT_CTX, VCL_REAL r)
294
{
295
296 18
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
297 18
        assert(ctx->syntax == 40 || ctx->syntax == 41);
298
        /*
299
         * We need to be careful because non-integer numbers have imprecise
300
         * IEE754 represenation (4.1 is 0x1.0666666666666p+2 = 4.09999...)
301
         * By scaling up and rounding, this is taken care of.
302
         */
303 18
        return (round(r * 10) <= ctx->syntax);
304
}