| | 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 |
16240 |
int onearg(VRT_CTX, const char *f, int nargs) |
| 60 |
|
{ |
| 61 |
16240 |
if (nargs == 1) |
| 62 |
16160 |
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 |
16240 |
} |
| 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 |
1280 |
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 |
1280 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 114 |
|
|
| 115 |
1280 |
nargs = a->valid_s + a->valid_real + a->valid_integer; |
| 116 |
|
|
| 117 |
1280 |
if (!onearg(ctx, "bytes", nargs)) |
| 118 |
0 |
return (0); |
| 119 |
|
|
| 120 |
1280 |
if (a->valid_s) { |
| 121 |
960 |
errtxt = VNUM_2bytes(a->s, &r, 0); |
| 122 |
960 |
if (errtxt == NULL && r <= VCL_BYTES_MAX) |
| 123 |
440 |
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 |
1280 |
} |
| 141 |
|
|
| 142 |
|
VCL_INT v_matchproto_(td_std_integer) |
| 143 |
6080 |
vmod_integer(VRT_CTX, struct VARGS(integer) *a) |
| 144 |
|
{ |
| 145 |
6080 |
const char *p, *errtxt = NULL; |
| 146 |
|
double r, tmp; |
| 147 |
|
int nargs; |
| 148 |
|
|
| 149 |
6080 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 150 |
|
|
| 151 |
18240 |
nargs = a->valid_s + a->valid_boolean + a->valid_bytes + |
| 152 |
12160 |
a->valid_duration + a->valid_real + a->valid_time; |
| 153 |
|
|
| 154 |
6080 |
if (!onearg(ctx, "integer", nargs)) |
| 155 |
80 |
return (0); |
| 156 |
|
|
| 157 |
6000 |
r = NAN; |
| 158 |
6000 |
if (a->valid_boolean) |
| 159 |
40 |
return (a->boolean ? 1 : 0); |
| 160 |
|
|
| 161 |
5960 |
if (a->valid_bytes) |
| 162 |
80 |
return (a->bytes); |
| 163 |
|
|
| 164 |
5880 |
if (a->valid_s && a->s != NULL) { |
| 165 |
4240 |
p = a->s; |
| 166 |
4240 |
r = SF_Parse_Number(&p, 0, &errtxt); |
| 167 |
4240 |
if (!errno && *p == '\0' && modf(r, &tmp) == 0.0) |
| 168 |
3600 |
return ((VCL_INT)r); |
| 169 |
640 |
r = NAN; |
| 170 |
640 |
} |
| 171 |
|
|
| 172 |
2280 |
if (a->valid_duration) |
| 173 |
120 |
r = a->duration; |
| 174 |
|
|
| 175 |
2280 |
if (a->valid_real) |
| 176 |
360 |
r = a->real; |
| 177 |
|
|
| 178 |
2280 |
if (a->valid_time) |
| 179 |
240 |
r = a->time; |
| 180 |
|
|
| 181 |
2280 |
if (!isnan(r)) { |
| 182 |
720 |
r = trunc(r); |
| 183 |
720 |
if (r >= VRT_INTEGER_MIN && r <= VRT_INTEGER_MAX) |
| 184 |
640 |
return ((VCL_INT)r); |
| 185 |
80 |
} |
| 186 |
|
|
| 187 |
1640 |
if (a->valid_fallback) |
| 188 |
1440 |
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 |
6080 |
} |
| 196 |
|
|
| 197 |
|
VCL_IP |
| 198 |
3640 |
vmod_ip(VRT_CTX, struct VARGS(ip) *a) |
| 199 |
|
{ |
| 200 |
|
uintptr_t sn; |
| 201 |
|
void *p; |
| 202 |
3640 |
VCL_IP retval = NULL, fb = bogo_ip; |
| 203 |
|
|
| 204 |
3640 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 205 |
|
|
| 206 |
3640 |
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 |
3640 |
sn = WS_Snapshot(ctx->ws); |
| 215 |
3640 |
p = WS_Alloc(ctx->ws, vsa_suckaddr_len); |
| 216 |
3640 |
if (p == NULL) { |
| 217 |
0 |
VRT_fail(ctx, "std.ip: insufficient workspace"); |
| 218 |
0 |
return (fb); |
| 219 |
|
} |
| 220 |
|
|
| 221 |
3640 |
if (a->s != NULL) |
| 222 |
3600 |
retval = VSS_ResolveFirst( |
| 223 |
3600 |
p, a->s, a->valid_p ? a->p : "80", |
| 224 |
|
AF_UNSPEC, SOCK_STREAM, |
| 225 |
3600 |
a->resolve ? 0 : AI_NUMERICHOST|AI_NUMERICSERV); |
| 226 |
|
|
| 227 |
3640 |
if (retval != NULL) |
| 228 |
3080 |
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 |
3640 |
} |
| 237 |
|
|
| 238 |
|
VCL_REAL v_matchproto_(td_std_real) |
| 239 |
2480 |
vmod_real(VRT_CTX, struct VARGS(real) *a) |
| 240 |
|
{ |
| 241 |
|
VCL_REAL r; |
| 242 |
2480 |
const char *p, *errtxt = NULL; |
| 243 |
|
int nargs; |
| 244 |
|
|
| 245 |
2480 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 246 |
|
|
| 247 |
7440 |
nargs = a->valid_s + a->valid_integer + a->valid_boolean + a->valid_bytes + |
| 248 |
4960 |
a->valid_duration + a->valid_time; |
| 249 |
|
|
| 250 |
2480 |
if (!onearg(ctx, "real", nargs)) |
| 251 |
0 |
return (0); |
| 252 |
|
|
| 253 |
2480 |
if (a->valid_integer) |
| 254 |
120 |
return ((VCL_REAL)a->integer); |
| 255 |
|
|
| 256 |
2360 |
if (a->valid_boolean) |
| 257 |
40 |
return ((VCL_REAL)(a->boolean ? 1 : 0)); |
| 258 |
|
|
| 259 |
2320 |
if (a->valid_bytes) |
| 260 |
80 |
return ((VCL_REAL)a->bytes); |
| 261 |
|
|
| 262 |
2240 |
if (a->valid_duration) |
| 263 |
120 |
return ((VCL_REAL)a->duration); |
| 264 |
|
|
| 265 |
2120 |
if (a->valid_time) |
| 266 |
160 |
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 |
2480 |
} |
| 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 |
4240 |
vmod_time(VRT_CTX, struct VARGS(time)* a) |
| 294 |
|
{ |
| 295 |
|
double r; |
| 296 |
|
int nargs; |
| 297 |
|
|
| 298 |
4240 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 299 |
|
|
| 300 |
4240 |
nargs = a->valid_s + a->valid_real + a->valid_integer; |
| 301 |
|
|
| 302 |
4240 |
if (!onearg(ctx, "time", nargs)) |
| 303 |
0 |
return (0); |
| 304 |
|
|
| 305 |
4240 |
if (a->valid_integer) |
| 306 |
80 |
return ((VCL_REAL)a->integer); |
| 307 |
|
|
| 308 |
4160 |
if (a->valid_real) |
| 309 |
360 |
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 |
4240 |
} |
| 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 |
} |