| | varnish-cache/vmod/vmod_std_conversions.c |
0 |
|
/*- |
1 |
|
* Copyright (c) 2010-2015 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 |
|
|
31 |
|
#include "config.h" |
32 |
|
|
33 |
|
#include <ctype.h> |
34 |
|
#include <string.h> |
35 |
|
#include <stdlib.h> |
36 |
|
#include <sys/socket.h> |
37 |
|
|
38 |
|
#include <netdb.h> |
39 |
|
|
40 |
|
#include "cache/cache.h" |
41 |
|
|
42 |
|
#include "vnum.h" |
43 |
|
#include "vsa.h" |
44 |
|
#include "vss.h" |
45 |
|
#include "vtim.h" |
46 |
|
#include "vcc_std_if.h" |
47 |
|
|
48 |
|
/* |
49 |
|
* technically, as our VCL_INT is int64_t, its limits are INT64_MIN |
50 |
|
* .. INT64_MAX. |
51 |
|
* |
52 |
|
* We redistrict to VRT_INTEGER_MIN .. VRT_INTEGER_MAX |
53 |
|
*/ |
54 |
|
|
55 |
|
/* limited by using double for conversions */ |
56 |
|
#define VCL_BYTES_MAX ((INT64_C(1)<<53)-1) |
57 |
|
|
58 |
|
static |
59 |
15520 |
int onearg(VRT_CTX, const char *f, int nargs) |
60 |
|
{ |
61 |
15520 |
if (nargs == 1) |
62 |
15440 |
return (1); |
63 |
160 |
VRT_fail(ctx, "std.%s: %s arguments", f, |
64 |
80 |
nargs > 1 ? "too many" : "not enough"); |
65 |
80 |
return (0); |
66 |
15520 |
} |
67 |
|
|
68 |
|
/* |
69 |
|
* not handling real arg isfinite() / nan() : caller error |
70 |
|
* always trunc, never round |
71 |
|
*/ |
72 |
|
|
73 |
|
VCL_DURATION v_matchproto_(td_std_duration) |
74 |
2160 |
vmod_duration(VRT_CTX, struct VARGS(duration) *a) |
75 |
|
{ |
76 |
|
double r; |
77 |
|
int nargs; |
78 |
|
|
79 |
2160 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
80 |
|
|
81 |
2160 |
nargs = a->valid_s + a->valid_real + a->valid_integer; |
82 |
|
|
83 |
2160 |
if (!onearg(ctx, "duration", nargs)) |
84 |
0 |
return (0); |
85 |
|
|
86 |
2160 |
if (a->valid_real) |
87 |
240 |
return ((VCL_DURATION)a->real); |
88 |
|
|
89 |
1920 |
if (a->valid_integer) |
90 |
160 |
return ((VCL_DURATION)a->integer); |
91 |
|
|
92 |
1760 |
if (a->valid_s) { |
93 |
1760 |
r = VNUM_duration(a->s); |
94 |
1760 |
if (!isnan(r)) |
95 |
960 |
return (r); |
96 |
800 |
} |
97 |
|
|
98 |
800 |
if (a->valid_fallback) |
99 |
560 |
return (a->fallback); |
100 |
|
|
101 |
240 |
VRT_fail(ctx, "std.duration: conversion failed"); |
102 |
240 |
return (0); |
103 |
2160 |
} |
104 |
|
|
105 |
|
VCL_BYTES v_matchproto_(td_std_bytes) |
106 |
1200 |
vmod_bytes(VRT_CTX, struct VARGS(bytes) *a) |
107 |
|
{ |
108 |
|
uintmax_t r; |
109 |
|
VCL_REAL rr; |
110 |
|
int nargs; |
111 |
|
const char *errtxt; |
112 |
|
|
113 |
1200 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
114 |
|
|
115 |
1200 |
nargs = a->valid_s + a->valid_real + a->valid_integer; |
116 |
|
|
117 |
1200 |
if (!onearg(ctx, "bytes", nargs)) |
118 |
0 |
return (0); |
119 |
|
|
120 |
1200 |
if (a->valid_s) { |
121 |
880 |
errtxt = VNUM_2bytes(a->s, &r, 0); |
122 |
880 |
if (errtxt == NULL && r <= VCL_BYTES_MAX) |
123 |
360 |
return ((VCL_BYTES)r); |
124 |
520 |
} |
125 |
|
|
126 |
840 |
if (a->valid_real && !isnan(a->real) && a->real >= 0) { |
127 |
200 |
rr = trunc(a->real); |
128 |
200 |
if (rr <= (VCL_REAL)VCL_BYTES_MAX) |
129 |
200 |
return ((VCL_BYTES)rr); |
130 |
0 |
} |
131 |
|
|
132 |
640 |
if (a->valid_integer && a->integer >= 0) |
133 |
120 |
return ((VCL_BYTES)a->integer); |
134 |
|
|
135 |
520 |
if (a->valid_fallback) |
136 |
480 |
return (a->fallback); |
137 |
|
|
138 |
40 |
VRT_fail(ctx, "std.bytes: conversion failed"); |
139 |
40 |
return (0); |
140 |
1200 |
} |
141 |
|
|
142 |
|
VCL_INT v_matchproto_(td_std_integer) |
143 |
5760 |
vmod_integer(VRT_CTX, struct VARGS(integer) *a) |
144 |
|
{ |
145 |
5760 |
const char *p, *errtxt = NULL; |
146 |
|
double r, tmp; |
147 |
|
int nargs; |
148 |
|
|
149 |
5760 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
150 |
|
|
151 |
17280 |
nargs = a->valid_s + a->valid_bool + a->valid_bytes + |
152 |
11520 |
a->valid_duration + a->valid_real + a->valid_time; |
153 |
|
|
154 |
5760 |
if (!onearg(ctx, "integer", nargs)) |
155 |
80 |
return (0); |
156 |
|
|
157 |
5680 |
r = NAN; |
158 |
5680 |
if (a->valid_bool) |
159 |
40 |
return (a->bool ? 1 : 0); |
160 |
|
|
161 |
5640 |
if (a->valid_bytes) |
162 |
80 |
return (a->bytes); |
163 |
|
|
164 |
5560 |
if (a->valid_s && a->s != NULL) { |
165 |
4160 |
p = a->s; |
166 |
4160 |
r = SF_Parse_Number(&p, 0, &errtxt); |
167 |
4160 |
if (!errno && *p == '\0' && modf(r, &tmp) == 0.0) |
168 |
3520 |
return ((VCL_INT)r); |
169 |
640 |
r = NAN; |
170 |
640 |
} |
171 |
|
|
172 |
2040 |
if (a->valid_duration) |
173 |
120 |
r = a->duration; |
174 |
|
|
175 |
2040 |
if (a->valid_real) |
176 |
200 |
r = a->real; |
177 |
|
|
178 |
2040 |
if (a->valid_time) |
179 |
160 |
r = a->time; |
180 |
|
|
181 |
2040 |
if (!isnan(r)) { |
182 |
480 |
r = trunc(r); |
183 |
480 |
if (r >= VRT_INTEGER_MIN && r <= VRT_INTEGER_MAX) |
184 |
480 |
return ((VCL_INT)r); |
185 |
0 |
} |
186 |
|
|
187 |
1560 |
if (a->valid_fallback) |
188 |
1360 |
return (a->fallback); |
189 |
|
|
190 |
200 |
if (errtxt != NULL) |
191 |
80 |
VRT_fail(ctx, "std.integer: conversion failed: %s", errtxt); |
192 |
|
else |
193 |
120 |
VRT_fail(ctx, "std.integer: conversion failed"); |
194 |
200 |
return (0); |
195 |
5760 |
} |
196 |
|
|
197 |
|
VCL_IP |
198 |
3560 |
vmod_ip(VRT_CTX, struct VARGS(ip) *a) |
199 |
|
{ |
200 |
|
uintptr_t sn; |
201 |
|
void *p; |
202 |
3560 |
VCL_IP retval = NULL, fb = bogo_ip; |
203 |
|
|
204 |
3560 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
205 |
|
|
206 |
3560 |
if (a->valid_fallback) { |
207 |
960 |
if (a->fallback == NULL || !VSA_Sane(a->fallback)) { |
208 |
0 |
VRT_fail(ctx, "std.ip: invalid fallback"); |
209 |
0 |
return (fb); |
210 |
|
} |
211 |
960 |
fb = a->fallback; |
212 |
960 |
} |
213 |
|
|
214 |
3560 |
sn = WS_Snapshot(ctx->ws); |
215 |
3560 |
p = WS_Alloc(ctx->ws, vsa_suckaddr_len); |
216 |
3560 |
if (p == NULL) { |
217 |
0 |
VRT_fail(ctx, "std.ip: insufficient workspace"); |
218 |
0 |
return (fb); |
219 |
|
} |
220 |
|
|
221 |
3560 |
if (a->s != NULL) |
222 |
3520 |
retval = VSS_ResolveFirst( |
223 |
3520 |
p, a->s, a->valid_p ? a->p : "80", |
224 |
|
AF_UNSPEC, SOCK_STREAM, |
225 |
3520 |
a->resolve ? 0 : AI_NUMERICHOST|AI_NUMERICSERV); |
226 |
|
|
227 |
3560 |
if (retval != NULL) |
228 |
3000 |
return (retval); |
229 |
|
|
230 |
560 |
WS_Reset(ctx->ws, sn); |
231 |
|
|
232 |
560 |
if (!a->valid_fallback) |
233 |
0 |
VRT_fail(ctx, "std.ip: conversion failed"); |
234 |
|
|
235 |
560 |
return (fb); |
236 |
3560 |
} |
237 |
|
|
238 |
|
VCL_REAL v_matchproto_(td_std_real) |
239 |
2400 |
vmod_real(VRT_CTX, struct VARGS(real) *a) |
240 |
|
{ |
241 |
|
VCL_REAL r; |
242 |
2400 |
const char *p, *errtxt = NULL; |
243 |
|
int nargs; |
244 |
|
|
245 |
2400 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
246 |
|
|
247 |
7200 |
nargs = a->valid_s + a->valid_integer + a->valid_bool + a->valid_bytes + |
248 |
4800 |
a->valid_duration + a->valid_time; |
249 |
|
|
250 |
2400 |
if (!onearg(ctx, "real", nargs)) |
251 |
0 |
return (0); |
252 |
|
|
253 |
2400 |
if (a->valid_integer) |
254 |
120 |
return ((VCL_REAL)a->integer); |
255 |
|
|
256 |
2280 |
if (a->valid_bool) |
257 |
40 |
return ((VCL_REAL)(a->bool ? 1 : 0)); |
258 |
|
|
259 |
2240 |
if (a->valid_bytes) |
260 |
80 |
return ((VCL_REAL)a->bytes); |
261 |
|
|
262 |
2160 |
if (a->valid_duration) |
263 |
120 |
return ((VCL_REAL)a->duration); |
264 |
|
|
265 |
2040 |
if (a->valid_time) |
266 |
80 |
return ((VCL_REAL)a->time); |
267 |
|
|
268 |
1960 |
if (a->valid_s && a->s != NULL) { |
269 |
1680 |
p = a->s; |
270 |
1680 |
r = SF_Parse_Decimal(&p, 0, &errtxt); |
271 |
1680 |
if (!errno && *p == '\0') |
272 |
1400 |
return (r); |
273 |
280 |
} |
274 |
|
|
275 |
560 |
if (a->valid_fallback) |
276 |
360 |
return (a->fallback); |
277 |
|
|
278 |
200 |
if (errtxt != NULL) |
279 |
80 |
VRT_fail(ctx, "std.real: conversion failed: %s", errtxt); |
280 |
|
else |
281 |
120 |
VRT_fail(ctx, "std.real: conversion failed"); |
282 |
200 |
return (0); |
283 |
2400 |
} |
284 |
|
|
285 |
|
VCL_REAL v_matchproto_(td_std_round) |
286 |
80 |
vmod_round(VRT_CTX, VCL_REAL r) |
287 |
|
{ |
288 |
80 |
(void) ctx; |
289 |
80 |
return (round(r)); |
290 |
|
} |
291 |
|
|
292 |
|
VCL_TIME v_matchproto_(td_std_time) |
293 |
4000 |
vmod_time(VRT_CTX, struct VARGS(time)* a) |
294 |
|
{ |
295 |
|
double r; |
296 |
|
int nargs; |
297 |
|
|
298 |
4000 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
299 |
|
|
300 |
4000 |
nargs = a->valid_s + a->valid_real + a->valid_integer; |
301 |
|
|
302 |
4000 |
if (!onearg(ctx, "time", nargs)) |
303 |
0 |
return (0); |
304 |
|
|
305 |
4000 |
if (a->valid_integer) |
306 |
80 |
return ((VCL_REAL)a->integer); |
307 |
|
|
308 |
3920 |
if (a->valid_real) |
309 |
120 |
return ((VCL_REAL)a->real); |
310 |
|
|
311 |
3800 |
if (a->valid_s && a->s != NULL) { |
312 |
3680 |
r = VTIM_parse(a->s); |
313 |
3680 |
if (r) |
314 |
1200 |
return (r); |
315 |
|
|
316 |
2480 |
r = VNUM(a->s); |
317 |
|
|
318 |
2480 |
if (!isnan(r) && r > 0) |
319 |
560 |
return (r); |
320 |
1920 |
} |
321 |
|
|
322 |
2040 |
if (a->valid_fallback) |
323 |
2040 |
return (a->fallback); |
324 |
|
|
325 |
0 |
VRT_fail(ctx, "std.time: conversion failed"); |
326 |
0 |
return (0); |
327 |
4000 |
} |
328 |
|
|
329 |
|
VCL_STRING v_matchproto_(td_std_strftime) |
330 |
880 |
vmod_strftime(VRT_CTX, VCL_TIME t, VCL_STRING fmt) |
331 |
|
{ |
332 |
|
struct tm tm; |
333 |
|
time_t tt; |
334 |
|
size_t r; |
335 |
|
unsigned spc; |
336 |
|
char *s; |
337 |
|
|
338 |
880 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
339 |
|
|
340 |
880 |
tt = (time_t)(intmax_t)t; |
341 |
880 |
if (gmtime_r(&tt, &tm) == NULL) |
342 |
0 |
return (""); |
343 |
|
|
344 |
880 |
spc = WS_ReserveAll(ctx->ws); |
345 |
880 |
s = WS_Reservation(ctx->ws); |
346 |
880 |
r = strftime(s, spc, fmt, &tm); |
347 |
880 |
if (r == 0) { |
348 |
40 |
WS_Release(ctx->ws, 0); |
349 |
40 |
return (""); |
350 |
|
} |
351 |
840 |
r++; |
352 |
840 |
WS_Release(ctx->ws, r); |
353 |
840 |
return (s); |
354 |
880 |
} |
355 |
|
|
356 |
|
/* These functions are deprecated as of 2019-03-15 release */ |
357 |
|
|
358 |
|
VCL_INT v_matchproto_(td_std_real2integer) |
359 |
160 |
vmod_real2integer(VRT_CTX, VCL_REAL r, VCL_INT i) |
360 |
|
{ |
361 |
|
VCL_INT retval; |
362 |
|
|
363 |
160 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
364 |
|
|
365 |
160 |
if (!VRT_REAL_is_valid(r)) |
366 |
80 |
return (i); |
367 |
80 |
retval = (VCL_INT)round(r); |
368 |
80 |
if (!VRT_INT_is_valid(retval)) |
369 |
0 |
return (i); |
370 |
80 |
return (retval); |
371 |
160 |
} |
372 |
|
|
373 |
|
VCL_TIME v_matchproto_(td_std_real2time) |
374 |
240 |
vmod_real2time(VRT_CTX, VCL_REAL r, VCL_TIME t) |
375 |
|
{ |
376 |
240 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
377 |
|
|
378 |
240 |
if (!isfinite(r)) |
379 |
0 |
return (t); |
380 |
|
|
381 |
240 |
return (r); |
382 |
240 |
} |
383 |
|
|
384 |
|
VCL_INT v_matchproto_(td_std_time2integer) |
385 |
80 |
vmod_time2integer(VRT_CTX, VCL_TIME t, VCL_INT i) |
386 |
|
{ |
387 |
80 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
388 |
|
|
389 |
80 |
if (!isfinite(t)) |
390 |
0 |
return (i); |
391 |
80 |
t = round(t); |
392 |
80 |
if (t > VRT_INTEGER_MAX || t < VRT_INTEGER_MIN) |
393 |
0 |
return (i); |
394 |
80 |
return ((VCL_INT)t); |
395 |
80 |
} |
396 |
|
|
397 |
|
VCL_REAL v_matchproto_(td_std_time2real) |
398 |
80 |
vmod_time2real(VRT_CTX, VCL_TIME t, VCL_REAL r) |
399 |
|
{ |
400 |
80 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
401 |
|
|
402 |
80 |
if (!isfinite(t)) |
403 |
0 |
return (r); |
404 |
|
|
405 |
80 |
return (t); |
406 |
80 |
} |