| | varnish-cache/vmod/vmod_std.c |
0 |
|
/*- |
1 |
|
* Copyright (c) 2010-2017 Varnish Software AS |
2 |
|
* All rights reserved. |
3 |
|
* |
4 |
|
* Author: Poul-Henning Kamp <phk@FreeBSD.org> |
5 |
|
* |
6 |
|
* SPDX-License-Identifier: BSD-2-Clause |
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 |
|
|
30 |
|
#include "config.h" |
31 |
|
|
32 |
|
#include <sys/stat.h> |
33 |
|
|
34 |
|
#include <netinet/in.h> |
35 |
|
|
36 |
|
#include <ctype.h> |
37 |
|
#include <stdlib.h> |
38 |
|
#include <string.h> |
39 |
|
#include <syslog.h> |
40 |
|
#include <sys/socket.h> |
41 |
|
#include <fnmatch.h> |
42 |
|
|
43 |
|
#include "cache/cache.h" |
44 |
|
|
45 |
|
#include "vrnd.h" |
46 |
|
#include "vtcp.h" |
47 |
|
#include "vsa.h" |
48 |
|
#include "vtim.h" |
49 |
|
#include "vcl.h" |
50 |
|
|
51 |
|
#include "vcc_std_if.h" |
52 |
|
|
53 |
|
VCL_VOID v_matchproto_(td_std_set_ip_tos) |
54 |
4 |
vmod_set_ip_tos(VRT_CTX, VCL_INT tos) |
55 |
|
{ |
56 |
|
struct suckaddr *sa; |
57 |
4 |
int fam, itos = tos; |
58 |
|
|
59 |
4 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
60 |
4 |
AZ(SES_Get_local_addr(ctx->req->sp, &sa)); |
61 |
|
/* Silently ignore for non-IP addresses. */ |
62 |
4 |
if (VSA_Compare(sa, bogo_ip) == 0) |
63 |
2 |
return; |
64 |
2 |
fam = VSA_Get_Proto(sa); |
65 |
2 |
switch (fam) { |
66 |
|
case PF_INET: |
67 |
2 |
VTCP_Assert(setsockopt(ctx->req->sp->fd, |
68 |
|
IPPROTO_IP, IP_TOS, &itos, sizeof(itos))); |
69 |
2 |
break; |
70 |
|
case PF_INET6: |
71 |
0 |
VTCP_Assert(setsockopt(ctx->req->sp->fd, |
72 |
|
IPPROTO_IPV6, IPV6_TCLASS, &itos, sizeof(itos))); |
73 |
0 |
break; |
74 |
|
default: |
75 |
0 |
INCOMPL(); |
76 |
0 |
} |
77 |
4 |
} |
78 |
|
|
79 |
|
static const char * |
80 |
24 |
vmod_updown(VRT_CTX, int up, VCL_STRANDS s) |
81 |
|
{ |
82 |
|
unsigned u; |
83 |
|
char *b, *e; |
84 |
|
const char *p; |
85 |
|
int i; |
86 |
|
|
87 |
24 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
88 |
24 |
CHECK_OBJ_NOTNULL(s, STRANDS_MAGIC); |
89 |
24 |
u = WS_ReserveAll(ctx->ws); |
90 |
24 |
e = b = WS_Reservation(ctx->ws); |
91 |
24 |
e += u; |
92 |
48 |
for (i = 0; i < s->n && b < e; i++) { |
93 |
24 |
p = s->p[i]; |
94 |
4388 |
while (p != NULL && *p != '\0' && b < e) { |
95 |
4364 |
if (up) |
96 |
2164 |
*b++ = (char)toupper(*p++); |
97 |
|
else |
98 |
2200 |
*b++ = (char)tolower(*p++); |
99 |
|
} |
100 |
24 |
} |
101 |
24 |
if (b < e) |
102 |
24 |
*b = '\0'; |
103 |
24 |
b++; |
104 |
24 |
if (b > e) { |
105 |
0 |
WS_MarkOverflow(ctx->ws); |
106 |
0 |
WS_Release(ctx->ws, 0); |
107 |
0 |
return (NULL); |
108 |
|
} else { |
109 |
24 |
e = b; |
110 |
24 |
b = WS_Reservation(ctx->ws); |
111 |
24 |
WS_Release(ctx->ws, e - b); |
112 |
24 |
return (b); |
113 |
|
} |
114 |
24 |
} |
115 |
|
|
116 |
|
VCL_STRING v_matchproto_(td_std_toupper) |
117 |
8 |
vmod_toupper(VRT_CTX, VCL_STRANDS s) |
118 |
|
{ |
119 |
|
|
120 |
8 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
121 |
8 |
return (vmod_updown(ctx, 1, s)); |
122 |
|
} |
123 |
|
|
124 |
|
VCL_STRING v_matchproto_(td_std_tolower) |
125 |
16 |
vmod_tolower(VRT_CTX, VCL_STRANDS s) |
126 |
|
{ |
127 |
|
|
128 |
16 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
129 |
16 |
return (vmod_updown(ctx, 0, s)); |
130 |
|
} |
131 |
|
|
132 |
|
VCL_REAL v_matchproto_(td_std_random) |
133 |
10 |
vmod_random(VRT_CTX, VCL_REAL lo, VCL_REAL hi) |
134 |
|
{ |
135 |
|
double a; |
136 |
|
|
137 |
10 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
138 |
10 |
a = VRND_RandomTestableDouble(); |
139 |
10 |
a *= hi - lo; |
140 |
10 |
a += lo; |
141 |
10 |
return (a); |
142 |
|
} |
143 |
|
|
144 |
|
VCL_VOID v_matchproto_(td_std_log) |
145 |
296 |
vmod_log(VRT_CTX, VCL_STRANDS s) |
146 |
|
{ |
147 |
296 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
148 |
|
|
149 |
296 |
if (ctx->vsl != NULL) |
150 |
232 |
VSLbs(ctx->vsl, SLT_VCL_Log, s); |
151 |
|
else |
152 |
64 |
VSLs(SLT_VCL_Log, NO_VXID, s); |
153 |
296 |
} |
154 |
|
|
155 |
|
/* XXX use vsyslog() ? */ |
156 |
|
VCL_VOID v_matchproto_(td_std_syslog) |
157 |
10 |
vmod_syslog(VRT_CTX, VCL_INT fac, VCL_STRANDS s) |
158 |
|
{ |
159 |
|
const char *p; |
160 |
|
uintptr_t sn; |
161 |
|
|
162 |
10 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
163 |
10 |
sn = WS_Snapshot(ctx->ws); |
164 |
10 |
p = VRT_StrandsWS(ctx->ws, NULL, s); |
165 |
10 |
if (p != NULL) |
166 |
8 |
syslog((int)fac, "%s", p); |
167 |
10 |
WS_Reset(ctx->ws, sn); |
168 |
10 |
} |
169 |
|
|
170 |
|
VCL_BOOL v_matchproto_(td_std_file_exists) |
171 |
4 |
vmod_file_exists(VRT_CTX, VCL_STRING file_name) |
172 |
|
{ |
173 |
|
struct stat st; |
174 |
|
|
175 |
4 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
176 |
4 |
return (stat(file_name, &st) == 0); |
177 |
|
} |
178 |
|
|
179 |
|
VCL_VOID v_matchproto_(td_std_collect) |
180 |
26 |
vmod_collect(VRT_CTX, VCL_HEADER hdr, VCL_STRING sep) |
181 |
|
{ |
182 |
|
struct http *hp; |
183 |
|
|
184 |
26 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
185 |
26 |
if (hdr == NULL) { |
186 |
0 |
VRT_fail(ctx, "std.collect(): header argument is NULL"); |
187 |
0 |
return; |
188 |
|
} |
189 |
26 |
hp = VRT_selecthttp(ctx, hdr->where); |
190 |
26 |
if (hp == NULL) { |
191 |
2 |
VRT_fail(ctx, "std.collect(): header argument " |
192 |
|
"cannot be used here"); |
193 |
2 |
return; |
194 |
|
} |
195 |
24 |
http_CollectHdrSep(hp, hdr->what, sep); |
196 |
26 |
} |
197 |
|
|
198 |
|
VCL_BOOL v_matchproto_(td_std_healthy) |
199 |
74 |
vmod_healthy(VRT_CTX, VCL_BACKEND be) |
200 |
|
{ |
201 |
74 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
202 |
74 |
CHECK_OBJ_ORNULL(be, DIRECTOR_MAGIC); |
203 |
74 |
return (VRT_Healthy(ctx, be, NULL)); |
204 |
|
} |
205 |
|
|
206 |
|
VCL_INT v_matchproto_(td_std_port) |
207 |
224 |
vmod_port(VRT_CTX, VCL_IP ip) |
208 |
|
{ |
209 |
224 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
210 |
224 |
if (ip == NULL) |
211 |
0 |
return (0); |
212 |
224 |
return (VSA_Port(ip)); |
213 |
224 |
} |
214 |
|
|
215 |
|
VCL_VOID v_matchproto_(td_std_rollback) |
216 |
46 |
vmod_rollback(VRT_CTX, VCL_HTTP hp) |
217 |
|
{ |
218 |
46 |
VRT_Rollback(ctx, hp); |
219 |
46 |
} |
220 |
|
|
221 |
|
VCL_VOID v_matchproto_(td_std_timestamp) |
222 |
42 |
vmod_timestamp(VRT_CTX, VCL_STRING label) |
223 |
|
{ |
224 |
|
|
225 |
42 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
226 |
42 |
if (label == NULL) |
227 |
0 |
return; |
228 |
42 |
if (*label == '\0') |
229 |
0 |
return; |
230 |
42 |
if (ctx->bo != NULL && ctx->req == NULL) { |
231 |
|
/* Called from backend vcl methods */ |
232 |
2 |
CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC); |
233 |
2 |
VSLb_ts_busyobj(ctx->bo, label, VTIM_real()); |
234 |
42 |
} else if (ctx->req != NULL) { |
235 |
|
/* Called from request vcl methods */ |
236 |
38 |
CHECK_OBJ(ctx->req, REQ_MAGIC); |
237 |
38 |
VSLb_ts_req(ctx->req, label, VTIM_real()); |
238 |
38 |
} |
239 |
42 |
} |
240 |
|
|
241 |
|
VCL_BOOL v_matchproto_(td_std_cache_req_body) |
242 |
70 |
vmod_cache_req_body(VRT_CTX, VCL_BYTES size) |
243 |
|
{ |
244 |
70 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
245 |
70 |
size = vmax_t(VCL_BYTES, size, 0); |
246 |
70 |
if (VRT_CacheReqBody(ctx, (size_t)size) < 0) |
247 |
10 |
return (0); |
248 |
60 |
return (1); |
249 |
70 |
} |
250 |
|
|
251 |
|
VCL_STRING v_matchproto_(td_std_strstr) |
252 |
6 |
vmod_strstr(VRT_CTX, VCL_STRING s1, VCL_STRING s2) |
253 |
|
{ |
254 |
6 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
255 |
6 |
if (s1 == NULL || s2 == NULL) |
256 |
2 |
return (NULL); |
257 |
4 |
return (strstr(s1, s2)); |
258 |
6 |
} |
259 |
|
|
260 |
|
VCL_STRING v_matchproto_(td_std_getenv) |
261 |
6 |
vmod_getenv(VRT_CTX, VCL_STRING name) |
262 |
|
{ |
263 |
6 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
264 |
6 |
if (name == NULL || *name == '\0') |
265 |
2 |
return (NULL); |
266 |
4 |
return (getenv(name)); |
267 |
6 |
} |
268 |
|
|
269 |
|
VCL_VOID v_matchproto_(td_std_late_100_continue) |
270 |
10 |
vmod_late_100_continue(VRT_CTX, VCL_BOOL late) |
271 |
|
{ |
272 |
10 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
273 |
10 |
assert(ctx->method == VCL_MET_RECV); |
274 |
10 |
CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC); |
275 |
10 |
if (ctx->req->want100cont) |
276 |
10 |
ctx->req->late100cont = late; |
277 |
10 |
} |
278 |
|
|
279 |
|
VCL_BOOL v_matchproto_(td_std_syntax) |
280 |
12 |
vmod_syntax(VRT_CTX, VCL_REAL r) |
281 |
|
{ |
282 |
|
|
283 |
12 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
284 |
12 |
assert(ctx->syntax == 40 || ctx->syntax == 41); |
285 |
|
/* |
286 |
|
* We need to be careful because non-integer numbers have imprecise |
287 |
|
* IEE754 representation (4.1 is 0x1.0666666666666p+2 = 4.09999...) |
288 |
|
* By scaling up and rounding, this is taken care of. |
289 |
|
*/ |
290 |
12 |
return (round(r * 10) <= ctx->syntax); |
291 |
|
} |
292 |
|
|
293 |
|
VCL_BOOL v_matchproto_(td_std_fnmatch) |
294 |
124 |
vmod_fnmatch(VRT_CTX, VCL_STRING pattern, VCL_STRING subject, |
295 |
|
VCL_BOOL pathname, VCL_BOOL noescape, VCL_BOOL period) |
296 |
|
{ |
297 |
124 |
int flags = 0; |
298 |
|
|
299 |
124 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
300 |
124 |
if (pattern == NULL) { |
301 |
2 |
VRT_fail(ctx, "std.fnmatch(): pattern is NULL"); |
302 |
2 |
return (0); |
303 |
|
} |
304 |
122 |
if (subject == NULL) { |
305 |
2 |
VRT_fail(ctx, "std.fnmatch(): subject is NULL"); |
306 |
2 |
return (0); |
307 |
|
} |
308 |
|
|
309 |
120 |
if (pathname) |
310 |
90 |
flags |= FNM_PATHNAME; |
311 |
120 |
if (noescape) |
312 |
30 |
flags |= FNM_NOESCAPE; |
313 |
120 |
if (period) |
314 |
30 |
flags |= FNM_PERIOD; |
315 |
120 |
return (fnmatch(pattern, subject, flags) != FNM_NOMATCH); |
316 |
124 |
} |
317 |
|
|
318 |
|
static const void * const priv_task_id_ban = &priv_task_id_ban; |
319 |
|
|
320 |
|
VCL_BOOL v_matchproto_(td_std_ban) |
321 |
44 |
vmod_ban(VRT_CTX, VCL_STRING s) |
322 |
|
{ |
323 |
|
struct vmod_priv *priv_task; |
324 |
|
VCL_STRING r; |
325 |
|
|
326 |
44 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
327 |
|
|
328 |
44 |
r = VRT_ban_string(ctx, s); |
329 |
44 |
priv_task = VRT_priv_task_get(ctx, priv_task_id_ban); |
330 |
|
|
331 |
44 |
if (r == NULL && priv_task == NULL) |
332 |
20 |
return (1); |
333 |
|
|
334 |
24 |
if (priv_task == NULL) |
335 |
4 |
priv_task = VRT_priv_task(ctx, priv_task_id_ban); |
336 |
|
|
337 |
24 |
if (priv_task == NULL) { |
338 |
0 |
VRT_fail(ctx, "std.ban(): no priv_task (out of workspace?)"); |
339 |
0 |
return (0); |
340 |
|
} |
341 |
|
|
342 |
|
/* |
343 |
|
* TRUST_ME: the ban error is const. We save it in the un-const priv |
344 |
|
* pointer, but promise to only ever return it as a (const) VCL_STRING |
345 |
|
*/ |
346 |
24 |
priv_task->priv = TRUST_ME(r); |
347 |
|
|
348 |
24 |
return (r == NULL); |
349 |
44 |
} |
350 |
|
|
351 |
|
VCL_STRING v_matchproto_(td_std_ban_error) |
352 |
24 |
vmod_ban_error(VRT_CTX) |
353 |
|
{ |
354 |
|
struct vmod_priv *priv_task; |
355 |
|
VCL_STRING r; |
356 |
|
|
357 |
24 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
358 |
|
|
359 |
24 |
priv_task = VRT_priv_task_get(ctx, priv_task_id_ban); |
360 |
24 |
if (priv_task == NULL) |
361 |
0 |
return (""); |
362 |
|
|
363 |
24 |
r = priv_task->priv; |
364 |
24 |
if (r == NULL) |
365 |
2 |
r = ""; |
366 |
24 |
return (r); |
367 |
24 |
} |
368 |
|
|
369 |
|
VCL_TIME v_matchproto_(td_std_now) |
370 |
4 |
vmod_now(VRT_CTX) |
371 |
|
{ |
372 |
|
|
373 |
4 |
(void) ctx; |
374 |
4 |
return (VTIM_real()); |
375 |
|
} |
376 |
|
|
377 |
|
VCL_DURATION v_matchproto_(td_std_timed_call) |
378 |
2 |
vmod_timed_call(VRT_CTX, VCL_SUB sub) |
379 |
|
{ |
380 |
|
vtim_mono b; |
381 |
|
|
382 |
2 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
383 |
2 |
b = VTIM_mono(); |
384 |
2 |
VRT_call(ctx, sub); |
385 |
2 |
return (VTIM_mono() - b); |
386 |
|
} |