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