| | varnish-cache/lib/libvarnishapi/vsl_arg.c |
0 |
|
/*- |
1 |
|
* Copyright (c) 2006 Verdens Gang AS |
2 |
|
* Copyright (c) 2006-2015 Varnish Software AS |
3 |
|
* All rights reserved. |
4 |
|
* |
5 |
|
* Author: Poul-Henning Kamp <phk@phk.freebsd.dk> |
6 |
|
* Author: Martin Blix Grydeland <martin@varnish-software.com> |
7 |
|
* |
8 |
|
* SPDX-License-Identifier: BSD-2-Clause |
9 |
|
* |
10 |
|
* Redistribution and use in source and binary forms, with or without |
11 |
|
* modification, are permitted provided that the following conditions |
12 |
|
* are met: |
13 |
|
* 1. Redistributions of source code must retain the above copyright |
14 |
|
* notice, this list of conditions and the following disclaimer. |
15 |
|
* 2. Redistributions in binary form must reproduce the above copyright |
16 |
|
* notice, this list of conditions and the following disclaimer in the |
17 |
|
* documentation and/or other materials provided with the distribution. |
18 |
|
* |
19 |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
20 |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
21 |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
22 |
|
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
23 |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
24 |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
25 |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
26 |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
27 |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
28 |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 |
|
* SUCH DAMAGE. |
30 |
|
*/ |
31 |
|
|
32 |
|
#include "config.h" |
33 |
|
|
34 |
|
#include <ctype.h> |
35 |
|
#include <limits.h> |
36 |
|
#include <math.h> |
37 |
|
#include <stdio.h> |
38 |
|
#include <stdlib.h> |
39 |
|
|
40 |
|
#include "vdef.h" |
41 |
|
#include "vas.h" |
42 |
|
#include "miniobj.h" |
43 |
|
|
44 |
|
#include "vbm.h" |
45 |
|
#include "vnum.h" |
46 |
|
#include "vqueue.h" |
47 |
|
#include "vre.h" |
48 |
|
#include "vsb.h" |
49 |
|
|
50 |
|
#include "vapi/vsl.h" |
51 |
|
|
52 |
|
#include "vsl_api.h" |
53 |
|
|
54 |
|
/*-------------------------------------------------------------------- |
55 |
|
* Look up a tag |
56 |
|
* 0..255 tag number |
57 |
|
* -1 no tag matches |
58 |
|
* -2 multiple tags match |
59 |
|
*/ |
60 |
|
|
61 |
|
int |
62 |
39375 |
VSL_Name2Tag(const char *name, int l) |
63 |
|
{ |
64 |
|
int i, n; |
65 |
|
|
66 |
39375 |
if (l == -1) |
67 |
3717 |
l = strlen(name); |
68 |
39375 |
n = -1; |
69 |
1799679 |
for (i = 0; i < SLT__MAX; i++) { |
70 |
1799343 |
if (VSL_tags[i] != NULL && |
71 |
1705536 |
!strncasecmp(name, VSL_tags[i], l)) { |
72 |
39753 |
if (strlen(VSL_tags[i]) == l) { |
73 |
|
/* Exact match */ |
74 |
39039 |
return (i); |
75 |
|
} |
76 |
714 |
if (n == -1) |
77 |
84 |
n = i; |
78 |
|
else |
79 |
630 |
n = -2; |
80 |
714 |
} |
81 |
1760304 |
} |
82 |
336 |
return (n); |
83 |
39375 |
} |
84 |
|
|
85 |
|
int |
86 |
4935 |
VSL_Glob2Tags(const char *glob, int l, VSL_tagfind_f *func, void *priv) |
87 |
|
{ |
88 |
4935 |
const char *p1 = NULL; |
89 |
4935 |
const char *p2 = NULL; |
90 |
|
const char *e, *p; |
91 |
4935 |
int i, l1 = 0, l2 = 0, r = 0; |
92 |
|
|
93 |
4935 |
AN(glob); |
94 |
4935 |
if (l >= 0) |
95 |
1239 |
e = glob + l; |
96 |
|
else |
97 |
3696 |
e = strchr(glob, '\0'); |
98 |
4935 |
if (glob == e) |
99 |
42 |
return (-1); // Empty pattern cannot match |
100 |
|
|
101 |
39900 |
for (p = glob; p < e; p++) |
102 |
35448 |
if (*p == '*') |
103 |
441 |
break; |
104 |
|
|
105 |
4893 |
if (p == e) { // No wildcard |
106 |
4452 |
i = VSL_Name2Tag(glob, l); |
107 |
4452 |
if (i < 0) |
108 |
189 |
return (i); |
109 |
4263 |
if (func != NULL) |
110 |
4263 |
(func)(i, priv); |
111 |
4263 |
return (1); |
112 |
|
} |
113 |
|
|
114 |
441 |
if (p != glob) { // Prefix match |
115 |
294 |
p1 = glob; |
116 |
294 |
l1 = p - p1; |
117 |
294 |
} |
118 |
|
|
119 |
441 |
if (p != e - 1) { // Postfix match |
120 |
210 |
p2 = p + 1; |
121 |
210 |
l2 = e - p2; |
122 |
210 |
} |
123 |
|
|
124 |
840 |
for (p++; p < e; p++) |
125 |
525 |
if (*p == '*') |
126 |
126 |
return (-3); // More than one wildcard |
127 |
|
|
128 |
80955 |
for (i = 0; i < SLT__MAX; i++) { |
129 |
80640 |
p = VSL_tags[i]; |
130 |
80640 |
if (p == NULL) |
131 |
51345 |
continue; |
132 |
29295 |
e = strchr(p, '\0'); |
133 |
29295 |
if ((e - p) - l1 < l2) |
134 |
2058 |
continue; |
135 |
27237 |
if (p1 != NULL && strncasecmp(p, p1, l1)) |
136 |
19761 |
continue; |
137 |
7476 |
if (p2 != NULL && strncasecmp(e - l2, p2, l2)) |
138 |
3360 |
continue; |
139 |
4116 |
if (func != NULL) |
140 |
4116 |
(func)(i, priv); |
141 |
4116 |
r++; |
142 |
4116 |
} |
143 |
315 |
if (r == 0) |
144 |
21 |
return (-1); |
145 |
294 |
return (r); |
146 |
4935 |
} |
147 |
|
|
148 |
|
int |
149 |
966 |
VSL_List2Tags(const char *list, int l, VSL_tagfind_f *func, void *priv) |
150 |
|
{ |
151 |
|
const char *p, *b, *e; |
152 |
966 |
int r, t = 0; |
153 |
|
|
154 |
966 |
p = list; |
155 |
966 |
if (l >= 0) |
156 |
63 |
e = p + l; |
157 |
|
else |
158 |
903 |
e = strchr(p, '\0'); |
159 |
2016 |
while (p < e) { |
160 |
1575 |
while (p < e && *p == ',') |
161 |
336 |
p++; |
162 |
1239 |
if (p == e) |
163 |
21 |
break; |
164 |
1218 |
b = p; |
165 |
8064 |
while (p < e && *p != ',') |
166 |
6846 |
p++; |
167 |
1218 |
r = VSL_Glob2Tags(b, p - b, func, priv); |
168 |
1218 |
if (r < 0) |
169 |
168 |
return (r); |
170 |
1050 |
t += r; |
171 |
|
} |
172 |
798 |
if (t == 0) |
173 |
21 |
return (-1); |
174 |
777 |
return (t); |
175 |
966 |
} |
176 |
|
|
177 |
|
const char *VSLQ_grouping[VSL_g__MAX] = { |
178 |
|
[VSL_g_raw] = "raw", |
179 |
|
[VSL_g_vxid] = "vxid", |
180 |
|
[VSL_g_request] = "request", |
181 |
|
[VSL_g_session] = "session", |
182 |
|
}; |
183 |
|
|
184 |
|
int |
185 |
4725 |
VSLQ_Name2Grouping(const char *name, int l) |
186 |
|
{ |
187 |
|
int i, n; |
188 |
|
|
189 |
4725 |
AN(name); |
190 |
4725 |
if (l == -1) |
191 |
294 |
l = strlen(name); |
192 |
4725 |
n = -1; |
193 |
8463 |
for (i = 0; i < VSL_g__MAX; i++) { |
194 |
8421 |
if (!strncasecmp(name, VSLQ_grouping[i], l)) { |
195 |
4725 |
if (strlen(VSLQ_grouping[i]) == l) { |
196 |
|
/* Exact match */ |
197 |
4683 |
return (i); |
198 |
|
} |
199 |
42 |
if (n == -1) |
200 |
21 |
n = i; |
201 |
|
else |
202 |
21 |
n = -2; |
203 |
42 |
} |
204 |
3738 |
} |
205 |
42 |
return (n); |
206 |
4725 |
} |
207 |
|
|
208 |
|
void v_matchproto_(VSL_tagfind_f) |
209 |
3822 |
vsl_vbm_bitset(int bit, void *priv) |
210 |
|
{ |
211 |
|
|
212 |
3822 |
vbit_set((struct vbitmap *)priv, bit); |
213 |
3822 |
} |
214 |
|
|
215 |
|
void v_matchproto_(VSL_tagfind_f) |
216 |
882 |
vsl_vbm_bitclr(int bit, void *priv) |
217 |
|
{ |
218 |
|
|
219 |
882 |
vbit_clr((struct vbitmap *)priv, bit); |
220 |
882 |
} |
221 |
|
|
222 |
|
static int |
223 |
798 |
vsl_ix_arg(struct VSL_data *vsl, int opt, const char *arg) |
224 |
|
{ |
225 |
|
int i; |
226 |
|
|
227 |
798 |
CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC); |
228 |
798 |
vsl->flags |= F_SEEN_ixIX; |
229 |
|
|
230 |
1596 |
i = VSL_List2Tags(arg, -1, opt == 'x' ? vsl_vbm_bitset : vsl_vbm_bitclr, |
231 |
798 |
vsl->vbm_suppress); |
232 |
798 |
if (i == -1) |
233 |
42 |
return (vsl_diag(vsl, "-%c: \"%s\" matches zero tags", |
234 |
21 |
(char)opt, arg)); |
235 |
777 |
else if (i == -2) |
236 |
42 |
return (vsl_diag(vsl, "-%c: \"%s\" is ambiguous", |
237 |
21 |
(char)opt, arg)); |
238 |
756 |
else if (i == -3) |
239 |
84 |
return (vsl_diag(vsl, "-%c: Syntax error in \"%s\"", |
240 |
42 |
(char)opt, arg)); |
241 |
|
|
242 |
714 |
return (1); |
243 |
798 |
} |
244 |
|
|
245 |
|
static int |
246 |
168 |
vsl_IX_arg(struct VSL_data *vsl, int opt, const char *arg) |
247 |
|
{ |
248 |
|
int i, l, off, err; |
249 |
|
const char *b, *e; |
250 |
|
vre_t *vre; |
251 |
|
struct vsb vsb[1]; |
252 |
|
struct vslf *vslf; |
253 |
168 |
struct vbitmap *tags = NULL; |
254 |
|
char errbuf[VRE_ERROR_LEN]; |
255 |
|
|
256 |
|
|
257 |
168 |
CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC); |
258 |
168 |
AN(arg); |
259 |
168 |
vsl->flags |= F_SEEN_ixIX; |
260 |
|
|
261 |
168 |
b = arg; |
262 |
168 |
e = strchr(b, ':'); |
263 |
168 |
if (e) { |
264 |
63 |
tags = vbit_new(SLT__MAX); |
265 |
63 |
AN(tags); |
266 |
63 |
l = e - b; |
267 |
63 |
i = VSL_List2Tags(b, l, vsl_vbm_bitset, tags); |
268 |
63 |
if (i < 0) |
269 |
63 |
vbit_destroy(tags); |
270 |
63 |
if (i == -1) |
271 |
42 |
return (vsl_diag(vsl, |
272 |
|
"-%c: \"%*.*s\" matches zero tags", |
273 |
21 |
(char)opt, l, l, b)); |
274 |
42 |
else if (i == -2) |
275 |
42 |
return (vsl_diag(vsl, |
276 |
|
"-%c: \"%*.*s\" is ambiguous", |
277 |
21 |
(char)opt, l, l, b)); |
278 |
21 |
else if (i <= -3) |
279 |
42 |
return (vsl_diag(vsl, |
280 |
|
"-%c: Syntax error in \"%*.*s\"", |
281 |
21 |
(char)opt, l, l, b)); |
282 |
0 |
b = e + 1; |
283 |
0 |
} |
284 |
|
|
285 |
105 |
vre = VRE_compile(b, vsl->C_opt ? VRE_CASELESS : 0, &err, &off, 1); |
286 |
105 |
if (vre == NULL) { |
287 |
21 |
if (tags) |
288 |
0 |
vbit_destroy(tags); |
289 |
21 |
AN(VSB_init(vsb, errbuf, sizeof errbuf)); |
290 |
21 |
AZ(VRE_error(vsb, err)); |
291 |
21 |
AZ(VSB_finish(vsb)); |
292 |
21 |
VSB_fini(vsb); |
293 |
42 |
return (vsl_diag(vsl, "-%c: Regex error at position %d (%s)", |
294 |
21 |
(char)opt, off, errbuf)); |
295 |
|
} |
296 |
|
|
297 |
84 |
ALLOC_OBJ(vslf, VSLF_MAGIC); |
298 |
84 |
AN(vslf); |
299 |
84 |
vslf->tags = tags; |
300 |
84 |
vslf->vre = vre; |
301 |
|
|
302 |
84 |
if (opt == 'I') |
303 |
42 |
VTAILQ_INSERT_TAIL(&vsl->vslf_select, vslf, list); |
304 |
|
else { |
305 |
42 |
assert(opt == 'X'); |
306 |
42 |
VTAILQ_INSERT_TAIL(&vsl->vslf_suppress, vslf, list); |
307 |
|
} |
308 |
|
|
309 |
84 |
return (1); |
310 |
168 |
} |
311 |
|
|
312 |
|
static int |
313 |
231 |
vsl_R_arg(struct VSL_data *vsl, const char *arg) |
314 |
|
{ |
315 |
231 |
char buf[32] = ""; |
316 |
|
char *p; |
317 |
|
long l; |
318 |
|
|
319 |
231 |
AN(arg); |
320 |
231 |
CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC); |
321 |
|
|
322 |
231 |
errno = 0; |
323 |
231 |
l = strtol(arg, &p, 0); |
324 |
231 |
if ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) |
325 |
0 |
return (vsl_diag(vsl, "-R: Range error")); |
326 |
231 |
if (l <= 0 || l > INT_MAX) |
327 |
63 |
return (vsl_diag(vsl, "-R: Range error")); |
328 |
168 |
vsl->R_opt_l = l; |
329 |
168 |
assert(p != arg); |
330 |
168 |
AN(p); |
331 |
168 |
if (*p == '\0') { |
332 |
0 |
vsl->R_opt_p = 1.0; |
333 |
0 |
return (1); |
334 |
|
} |
335 |
168 |
if (*p != '/' || p[1] == '\0') |
336 |
21 |
return (vsl_diag(vsl, "-R: Syntax error")); |
337 |
147 |
p++; |
338 |
147 |
if (strlen(p) > sizeof(buf) - 2) |
339 |
21 |
return (vsl_diag(vsl, "-R: Syntax error")); |
340 |
126 |
if (!isdigit(*p)) |
341 |
63 |
strcat(buf, "1"); |
342 |
126 |
strcat(buf, p); |
343 |
126 |
vsl->R_opt_p = VNUM_duration(buf); |
344 |
126 |
if (isnan(vsl->R_opt_p) || vsl->R_opt_p <= 0.0) |
345 |
84 |
return (vsl_diag(vsl, "-R: Syntax error: Invalid duration")); |
346 |
42 |
return (1); |
347 |
231 |
} |
348 |
|
|
349 |
|
int |
350 |
3318 |
VSL_Arg(struct VSL_data *vsl, int opt, const char *arg) |
351 |
|
{ |
352 |
|
int i; |
353 |
|
char *p; |
354 |
|
double d; |
355 |
|
long l; |
356 |
|
|
357 |
3318 |
CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC); |
358 |
|
/* If first option is 'i', set all bits for suppression */ |
359 |
3318 |
if ((opt == 'i' || opt == 'I') && !(vsl->flags & F_SEEN_ixIX)) |
360 |
145719 |
for (i = 0; i < SLT__MAX; i++) |
361 |
145719 |
vbit_set(vsl->vbm_suppress, i); |
362 |
|
|
363 |
3318 |
switch (opt) { |
364 |
315 |
case 'b': vsl->b_opt = 1; return (1); |
365 |
1470 |
case 'c': vsl->c_opt = 1; return (1); |
366 |
|
case 'C': |
367 |
|
/* Caseless regular expressions */ |
368 |
42 |
vsl->C_opt = 1; |
369 |
42 |
return (1); |
370 |
|
case 'E': |
371 |
189 |
vsl->E_opt = 1; |
372 |
189 |
vsl->c_opt = 1; |
373 |
189 |
return (1); |
374 |
798 |
case 'i': case 'x': return (vsl_ix_arg(vsl, opt, arg)); |
375 |
168 |
case 'I': case 'X': return (vsl_IX_arg(vsl, opt, arg)); |
376 |
|
case 'L': |
377 |
21 |
AN(arg); |
378 |
21 |
l = strtol(arg, &p, 0); |
379 |
21 |
while (isspace(*p)) |
380 |
0 |
p++; |
381 |
21 |
if (*p != '\0') |
382 |
0 |
return (vsl_diag(vsl, "-L: Syntax error")); |
383 |
21 |
if (l <= 0 || l > INT_MAX) |
384 |
21 |
return (vsl_diag(vsl, "-L: Range error")); |
385 |
0 |
vsl->L_opt = (int)l; |
386 |
0 |
return (1); |
387 |
|
case 'R': |
388 |
231 |
return (vsl_R_arg(vsl, arg)); |
389 |
|
case 'T': |
390 |
21 |
AN(arg); |
391 |
21 |
d = VNUM(arg); |
392 |
21 |
if (isnan(d)) |
393 |
0 |
return (vsl_diag(vsl, "-T: Syntax error")); |
394 |
21 |
if (d < 0.) |
395 |
0 |
return (vsl_diag(vsl, "-T: Range error")); |
396 |
21 |
vsl->T_opt = d; |
397 |
21 |
return (1); |
398 |
21 |
case 'v': vsl->v_opt = 1; return (1); |
399 |
|
default: |
400 |
42 |
return (0); |
401 |
|
} |
402 |
3318 |
} |