| | varnish-cache/vmod/vmod_blob.c |
| 0 |
|
/*- |
| 1 |
|
* Copyright 2015-2017 UPLEX - Nils Goroll Systemoptimierung |
| 2 |
|
* All rights reserved. |
| 3 |
|
* |
| 4 |
26757 |
* Authors: Nils Goroll <nils.goroll@uplex.de> |
| 5 |
69797 |
* Geoffrey Simmons <geoffrey.simmons@uplex.de> |
| 6 |
59797 |
* |
| 7 |
37640 |
* SPDX-License-Identifier: BSD-2-Clause |
| 8 |
34840 |
* |
| 9 |
34760 |
* Redistribution and use in source and binary forms, with or without |
| 10 |
23400 |
* modification, are permitted provided that the following conditions are met: |
| 11 |
10000 |
* 1. Redistributions of source code must retain the above copyright notice, |
| 12 |
|
* this list of conditions and the following disclaimer. |
| 13 |
|
* 2. Redistributions in binary form must reproduce the above copyright notice, |
| 14 |
|
* this list of conditions and the following disclaimer in the documentation |
| 15 |
|
* and/or other materials provided with the distribution. |
| 16 |
|
* |
| 17 |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY |
| 18 |
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 19 |
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 20 |
|
* DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY |
| 21 |
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 22 |
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 23 |
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 24 |
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 |
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 26 |
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 |
|
* |
| 28 |
|
*/ |
| 29 |
|
|
| 30 |
|
#include "config.h" |
| 31 |
|
#include <string.h> |
| 32 |
|
|
| 33 |
|
#include "cache/cache.h" |
| 34 |
|
|
| 35 |
|
#include "vcc_blob_if.h" |
| 36 |
|
#include "vmod_blob.h" |
| 37 |
|
|
| 38 |
|
#define VMOD_BLOB_TYPE 0xfade4faa |
| 39 |
|
|
| 40 |
|
struct vmod_blob_blob { |
| 41 |
|
unsigned magic; |
| 42 |
|
#define VMOD_BLOB_MAGIC 0xfade4fa9 |
| 43 |
|
struct vrt_blob blob; |
| 44 |
|
void *freeptr; |
| 45 |
|
char *encoding[__MAX_ENCODING][2]; |
| 46 |
|
pthread_mutex_t lock; |
| 47 |
|
}; |
| 48 |
|
|
| 49 |
|
#define B64_FUNCS \ |
| 50 |
|
.decode_l = base64_decode_l, \ |
| 51 |
|
.decode = base64_decode, \ |
| 52 |
|
.encode = base64_encode |
| 53 |
|
|
| 54 |
|
static const struct vmod_blob_fptr { |
| 55 |
|
len_f *const decode_l; |
| 56 |
|
decode_f *const decode; |
| 57 |
|
len_f *const encode_l; |
| 58 |
|
encode_f *const encode; |
| 59 |
|
} func[__MAX_ENCODING] = { |
| 60 |
|
[IDENTITY] = { |
| 61 |
|
.decode_l = id_decode_l, |
| 62 |
|
.decode = id_decode, |
| 63 |
|
.encode_l = id_encode_l, |
| 64 |
|
.encode = id_encode |
| 65 |
|
}, |
| 66 |
|
[BASE64] = { |
| 67 |
|
B64_FUNCS, |
| 68 |
|
.encode_l = base64_encode_l |
| 69 |
|
}, |
| 70 |
|
[BASE64URL] = { |
| 71 |
|
B64_FUNCS, |
| 72 |
|
.encode_l = base64_encode_l |
| 73 |
|
}, |
| 74 |
|
[BASE64URLNOPAD] = { |
| 75 |
|
B64_FUNCS, |
| 76 |
|
.encode_l = base64nopad_encode_l |
| 77 |
|
}, |
| 78 |
|
[BASE64CF] = { |
| 79 |
|
B64_FUNCS, |
| 80 |
|
.encode_l = base64_encode_l |
| 81 |
|
}, |
| 82 |
|
[HEX] = { |
| 83 |
|
.decode_l = hex_decode_l, |
| 84 |
|
.decode = hex_decode, |
| 85 |
|
.encode_l = hex_encode_l, |
| 86 |
|
.encode = hex_encode |
| 87 |
|
}, |
| 88 |
|
[URL] = { |
| 89 |
|
.decode_l = url_decode_l, |
| 90 |
|
.decode = url_decode, |
| 91 |
|
.encode_l = url_encode_l, |
| 92 |
|
.encode = url_encode |
| 93 |
|
}, |
| 94 |
|
}; |
| 95 |
|
|
| 96 |
|
#undef B64_FUNCS |
| 97 |
|
|
| 98 |
|
#define ERR(ctx, msg) \ |
| 99 |
|
VRT_fail((ctx), "vmod blob error: " msg) |
| 100 |
|
|
| 101 |
|
#define VERR(ctx, fmt, ...) \ |
| 102 |
|
VRT_fail((ctx), "vmod blob error: " fmt, __VA_ARGS__) |
| 103 |
|
|
| 104 |
|
#define ERRINVAL(ctx, enc) \ |
| 105 |
|
VERR((ctx), "cannot decode, illegal encoding beginning with \"%s\"", \ |
| 106 |
|
(enc)) |
| 107 |
|
|
| 108 |
|
#define VERRNOMEM(ctx, fmt, ...) \ |
| 109 |
|
VERR((ctx), fmt ", out of space", __VA_ARGS__) |
| 110 |
|
|
| 111 |
|
#define ERRNOMEM(ctx, msg) \ |
| 112 |
|
ERR((ctx), msg ", out of space") |
| 113 |
|
|
| 114 |
|
static char empty[1] = { '\0' }; |
| 115 |
|
|
| 116 |
|
static enum encoding |
| 117 |
46480 |
parse_encoding(VCL_ENUM e) |
| 118 |
|
{ |
| 119 |
|
#define VMODENUM(n) \ |
| 120 |
|
do { \ |
| 121 |
|
if (e == VENUM(n)) return (n); \ |
| 122 |
|
} while (0); |
| 123 |
|
#include "vmod_blob_tbl_encodings.h" |
| 124 |
0 |
WRONG("illegal encoding enum"); |
| 125 |
|
} |
| 126 |
|
|
| 127 |
|
static enum case_e |
| 128 |
26757 |
parse_case(VCL_ENUM e) |
| 129 |
|
{ |
| 130 |
|
#define VMODENUM(n) \ |
| 131 |
|
do { \ |
| 132 |
|
if (e == VENUM(n)) return (n); \ |
| 133 |
|
} while (0); |
| 134 |
|
#include "vmod_blob_tbl_case.h" |
| 135 |
0 |
WRONG("illegal case enum"); |
| 136 |
|
} |
| 137 |
|
|
| 138 |
|
|
| 139 |
|
static inline size_t |
| 140 |
9280 |
decode_l(enum encoding dec, VCL_STRANDS s) |
| 141 |
|
{ |
| 142 |
9280 |
size_t len = 0; |
| 143 |
|
|
| 144 |
9280 |
AENC(dec); |
| 145 |
|
|
| 146 |
9280 |
CHECK_OBJ_NOTNULL(s, STRANDS_MAGIC); |
| 147 |
20400 |
for (int i = 0; i < s->n; i++) |
| 148 |
21040 |
if (s->p[i] != NULL && *s->p[i] != '\0') |
| 149 |
9920 |
len += strlen(s->p[i]); |
| 150 |
|
|
| 151 |
9280 |
return (func[dec].decode_l(len)); |
| 152 |
|
} |
| 153 |
|
|
| 154 |
|
static void |
| 155 |
1520 |
err_decode(VRT_CTX, const char *enc) |
| 156 |
|
{ |
| 157 |
1520 |
switch (errno) { |
| 158 |
|
case EINVAL: |
| 159 |
1360 |
ERRINVAL(ctx, enc); |
| 160 |
1360 |
break; |
| 161 |
|
case ENOMEM: |
| 162 |
160 |
ERRNOMEM(ctx, "cannot decode"); |
| 163 |
160 |
break; |
| 164 |
|
default: |
| 165 |
0 |
WRONG("invalid errno"); |
| 166 |
0 |
} |
| 167 |
1520 |
} |
| 168 |
|
|
| 169 |
|
static inline int |
| 170 |
27798 |
encodes_hex(enum encoding enc) |
| 171 |
|
{ |
| 172 |
27798 |
return (enc == HEX || enc == URL); |
| 173 |
|
} |
| 174 |
|
|
| 175 |
|
/* Require case DEFAULT for all encodings besides HEX and URL. */ |
| 176 |
|
|
| 177 |
|
static inline int |
| 178 |
26756 |
check_enc_case(VRT_CTX, VCL_ENUM encs, VCL_ENUM case_s, enum encoding enc, |
| 179 |
|
enum case_e kase) |
| 180 |
|
{ |
| 181 |
26756 |
if (!encodes_hex(enc) && kase != DEFAULT) { |
| 182 |
640 |
VERR(ctx, "case %s is illegal with encoding %s", case_s, encs); |
| 183 |
640 |
return (0); |
| 184 |
|
} |
| 185 |
26116 |
return (1); |
| 186 |
26756 |
} |
| 187 |
|
|
| 188 |
|
/* Objects */ |
| 189 |
|
|
| 190 |
|
VCL_VOID v_matchproto_(td_blob_blob__init) |
| 191 |
2000 |
vmod_blob__init(VRT_CTX, struct vmod_blob_blob **blobp, const char *vcl_name, |
| 192 |
|
VCL_ENUM decs, VCL_STRANDS strings) |
| 193 |
|
{ |
| 194 |
|
struct vmod_blob_blob *b; |
| 195 |
2000 |
enum encoding dec = parse_encoding(decs); |
| 196 |
|
void *buf; |
| 197 |
|
ssize_t len; |
| 198 |
|
|
| 199 |
2000 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 200 |
2000 |
AN(blobp); |
| 201 |
2000 |
AZ(*blobp); |
| 202 |
2000 |
AN(vcl_name); |
| 203 |
2000 |
AENC(dec); |
| 204 |
2000 |
CHECK_OBJ_NOTNULL(strings, STRANDS_MAGIC); |
| 205 |
|
|
| 206 |
2000 |
ALLOC_OBJ(b, VMOD_BLOB_MAGIC); |
| 207 |
2000 |
AN(b); |
| 208 |
2000 |
*blobp = b; |
| 209 |
2000 |
AZ(pthread_mutex_init(&b->lock, NULL)); |
| 210 |
|
|
| 211 |
2000 |
b->blob.magic = VRT_BLOB_MAGIC; |
| 212 |
2000 |
b->blob.type = VMOD_BLOB_TYPE; |
| 213 |
|
|
| 214 |
2000 |
len = decode_l(dec, strings); |
| 215 |
2000 |
if (len == 0) |
| 216 |
320 |
return; |
| 217 |
|
|
| 218 |
1680 |
assert(len > 0); |
| 219 |
|
|
| 220 |
1680 |
buf = malloc(len); |
| 221 |
1680 |
if (buf == NULL) { |
| 222 |
0 |
VERRNOMEM(ctx, "cannot create blob %s", vcl_name); |
| 223 |
0 |
return; |
| 224 |
|
} |
| 225 |
|
|
| 226 |
1680 |
errno = 0; |
| 227 |
1680 |
len = func[dec].decode(dec, buf, len, -1, strings); |
| 228 |
|
|
| 229 |
1680 |
if (len == -1) { |
| 230 |
320 |
assert(errno == EINVAL); |
| 231 |
320 |
free(buf); |
| 232 |
320 |
VERR(ctx, "cannot create blob %s, illegal encoding beginning " |
| 233 |
|
"with \"%s\"", vcl_name, strings->p[0]); |
| 234 |
320 |
return; |
| 235 |
|
} |
| 236 |
1360 |
if (len == 0) { |
| 237 |
0 |
free(buf); |
| 238 |
0 |
memcpy(&b->blob, vrt_null_blob, sizeof b->blob); |
| 239 |
0 |
return; |
| 240 |
|
} |
| 241 |
1360 |
b->blob.len = len; |
| 242 |
1360 |
b->blob.blob = b->freeptr = buf; |
| 243 |
2000 |
} |
| 244 |
|
|
| 245 |
|
VCL_BLOB v_matchproto_(td_blob_blob_get) |
| 246 |
4280 |
vmod_blob_get(VRT_CTX, struct vmod_blob_blob *b) |
| 247 |
|
{ |
| 248 |
4280 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 249 |
4280 |
CHECK_OBJ_NOTNULL(b, VMOD_BLOB_MAGIC); |
| 250 |
4280 |
CHECK_OBJ(&b->blob, VRT_BLOB_MAGIC); |
| 251 |
4280 |
return (&b->blob); |
| 252 |
|
} |
| 253 |
|
|
| 254 |
|
VCL_STRING v_matchproto_(td_blob_blob_encode) |
| 255 |
7080 |
vmod_blob_encode(VRT_CTX, struct vmod_blob_blob *b, VCL_ENUM encs, |
| 256 |
|
VCL_ENUM case_s) |
| 257 |
|
{ |
| 258 |
7080 |
enum encoding enc = parse_encoding(encs); |
| 259 |
7080 |
AENC(enc); |
| 260 |
7080 |
enum case_e kase = parse_case(case_s); |
| 261 |
|
|
| 262 |
7080 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 263 |
7080 |
CHECK_OBJ_NOTNULL(b, VMOD_BLOB_MAGIC); |
| 264 |
7080 |
CHECK_OBJ(&b->blob, VRT_BLOB_MAGIC); |
| 265 |
|
|
| 266 |
7080 |
if (!check_enc_case(ctx, encs, case_s, enc, kase)) |
| 267 |
320 |
return (NULL); |
| 268 |
6760 |
if (b->blob.len == 0) |
| 269 |
800 |
return (""); |
| 270 |
5960 |
if (kase == DEFAULT) |
| 271 |
3640 |
kase = LOWER; |
| 272 |
|
|
| 273 |
5960 |
if (b->encoding[enc][kase] == NULL) { |
| 274 |
2440 |
PTOK(pthread_mutex_lock(&b->lock)); |
| 275 |
2440 |
if (b->encoding[enc][kase] == NULL) { |
| 276 |
2440 |
ssize_t len = func[enc].encode_l(b->blob.len); |
| 277 |
|
|
| 278 |
2440 |
assert(len >= 0); |
| 279 |
2440 |
if (len == 0) |
| 280 |
0 |
b->encoding[enc][kase] = empty; |
| 281 |
|
else { |
| 282 |
2440 |
b->encoding[enc][kase] = malloc(len); |
| 283 |
2440 |
if (b->encoding[enc][kase] == NULL) |
| 284 |
0 |
ERRNOMEM(ctx, "cannot encode"); |
| 285 |
|
else { |
| 286 |
2440 |
char *s = b->encoding[enc][kase]; |
| 287 |
2440 |
len = |
| 288 |
4880 |
func[enc].encode( |
| 289 |
2440 |
enc, kase, s, len, |
| 290 |
2440 |
b->blob.blob, |
| 291 |
2440 |
b->blob.len); |
| 292 |
2440 |
assert(len >= 0); |
| 293 |
2440 |
if (len == 0) { |
| 294 |
0 |
free(s); |
| 295 |
0 |
b->encoding[enc][kase] = empty; |
| 296 |
0 |
} |
| 297 |
|
else |
| 298 |
2440 |
s[len] = '\0'; |
| 299 |
|
} |
| 300 |
|
} |
| 301 |
2440 |
} |
| 302 |
2440 |
PTOK(pthread_mutex_unlock(&b->lock)); |
| 303 |
2440 |
} |
| 304 |
5960 |
return (b->encoding[enc][kase]); |
| 305 |
7080 |
} |
| 306 |
|
|
| 307 |
|
VCL_VOID v_matchproto_(td_blob_blob__fini) |
| 308 |
1000 |
vmod_blob__fini(struct vmod_blob_blob **blobp) |
| 309 |
|
{ |
| 310 |
|
struct vmod_blob_blob *b; |
| 311 |
|
char *s; |
| 312 |
|
int i, j; |
| 313 |
|
|
| 314 |
1000 |
TAKE_OBJ_NOTNULL(b, blobp, VMOD_BLOB_MAGIC); |
| 315 |
1000 |
CHECK_OBJ(&b->blob, VRT_BLOB_MAGIC); |
| 316 |
|
|
| 317 |
1000 |
if (b->freeptr != NULL) { |
| 318 |
560 |
free(b->freeptr); |
| 319 |
560 |
b->blob.blob = NULL; |
| 320 |
560 |
} |
| 321 |
|
|
| 322 |
9000 |
for (i = 0; i < __MAX_ENCODING; i++) |
| 323 |
24000 |
for (j = 0; j < 2; j++) { |
| 324 |
16000 |
s = b->encoding[i][j]; |
| 325 |
16000 |
if (s != NULL && s != empty) { |
| 326 |
800 |
free(s); |
| 327 |
800 |
b->encoding[i][j] = NULL; |
| 328 |
800 |
} |
| 329 |
24000 |
} |
| 330 |
|
|
| 331 |
1000 |
PTOK(pthread_mutex_destroy(&b->lock)); |
| 332 |
1000 |
FREE_OBJ(b); |
| 333 |
1000 |
} |
| 334 |
|
|
| 335 |
|
/* Functions */ |
| 336 |
|
|
| 337 |
|
VCL_BLOB v_matchproto_(td_blob_decode) |
| 338 |
10440 |
vmod_decode(VRT_CTX, VCL_ENUM decs, VCL_INT length, VCL_STRANDS strings) |
| 339 |
|
{ |
| 340 |
10440 |
enum encoding dec = parse_encoding(decs); |
| 341 |
|
char *buf; |
| 342 |
|
ssize_t len; |
| 343 |
|
unsigned space; |
| 344 |
|
|
| 345 |
10440 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 346 |
10440 |
AENC(dec); |
| 347 |
10440 |
CHECK_OBJ_NOTNULL(strings, STRANDS_MAGIC); |
| 348 |
10440 |
CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC); |
| 349 |
|
|
| 350 |
10440 |
space = WS_ReserveAll(ctx->ws); |
| 351 |
10440 |
buf = WS_Reservation(ctx->ws); |
| 352 |
|
|
| 353 |
10440 |
if (length <= 0) |
| 354 |
7200 |
length = -1; |
| 355 |
10440 |
errno = 0; |
| 356 |
10440 |
len = func[dec].decode(dec, buf, space, length, strings); |
| 357 |
|
|
| 358 |
10440 |
if (len == -1) { |
| 359 |
720 |
err_decode(ctx, strings->p[0]); |
| 360 |
720 |
WS_Release(ctx->ws, 0); |
| 361 |
720 |
return (NULL); |
| 362 |
|
} |
| 363 |
9720 |
if (len == 0) { |
| 364 |
1680 |
WS_Release(ctx->ws, 0); |
| 365 |
1680 |
return (vrt_null_blob); |
| 366 |
|
} |
| 367 |
8040 |
WS_Release(ctx->ws, len); |
| 368 |
|
|
| 369 |
8040 |
assert(len > 0); |
| 370 |
|
|
| 371 |
8040 |
return (VRT_blob(ctx, "blob.decode", buf, len, VMOD_BLOB_TYPE)); |
| 372 |
10440 |
} |
| 373 |
|
|
| 374 |
|
static VCL_STRING |
| 375 |
18399 |
encode(VRT_CTX, enum encoding enc, enum case_e kase, VCL_BLOB b) |
| 376 |
|
{ |
| 377 |
|
ssize_t len; |
| 378 |
|
char *buf; |
| 379 |
|
unsigned space; |
| 380 |
|
|
| 381 |
18399 |
AENC(enc); |
| 382 |
|
|
| 383 |
18399 |
if (b == NULL) |
| 384 |
1080 |
return (NULL); |
| 385 |
|
|
| 386 |
17319 |
CHECK_OBJ(b, VRT_BLOB_MAGIC); |
| 387 |
17319 |
CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC); |
| 388 |
17319 |
space = WS_ReserveAll(ctx->ws); |
| 389 |
17319 |
buf = WS_Reservation(ctx->ws); |
| 390 |
|
|
| 391 |
17319 |
len = func[enc].encode(enc, kase, buf, space, b->blob, b->len); |
| 392 |
|
|
| 393 |
17319 |
if (len == -1) { |
| 394 |
200 |
ERRNOMEM(ctx, "cannot encode"); |
| 395 |
200 |
WS_Release(ctx->ws, 0); |
| 396 |
200 |
return (NULL); |
| 397 |
|
} |
| 398 |
17119 |
if (len == 0) { |
| 399 |
1440 |
WS_Release(ctx->ws, 0); |
| 400 |
1440 |
return (""); |
| 401 |
|
} |
| 402 |
15679 |
buf[len] = '\0'; |
| 403 |
15679 |
WS_Release(ctx->ws, len + 1); |
| 404 |
15679 |
return (buf); |
| 405 |
18399 |
} |
| 406 |
|
|
| 407 |
|
VCL_STRING v_matchproto_(td_blob_encode) |
| 408 |
12397 |
vmod_encode(VRT_CTX, VCL_ENUM encs, VCL_ENUM case_s, VCL_BLOB b) |
| 409 |
|
{ |
| 410 |
12397 |
enum encoding enc = parse_encoding(encs); |
| 411 |
12397 |
enum case_e kase = parse_case(case_s); |
| 412 |
|
|
| 413 |
12397 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 414 |
12397 |
if (!check_enc_case(ctx, encs, case_s, enc, kase)) |
| 415 |
320 |
return (NULL); |
| 416 |
12077 |
return (encode(ctx, enc, kase, b)); |
| 417 |
12397 |
} |
| 418 |
|
|
| 419 |
|
VCL_STRING v_matchproto_(td_blob_transcode) |
| 420 |
7280 |
vmod_transcode(VRT_CTX, VCL_ENUM decs, VCL_ENUM encs, VCL_ENUM case_s, |
| 421 |
|
VCL_INT length, VCL_STRANDS strings) |
| 422 |
|
{ |
| 423 |
7280 |
enum encoding dec = parse_encoding(decs); |
| 424 |
7280 |
enum encoding enc = parse_encoding(encs); |
| 425 |
7280 |
enum case_e kase = parse_case(case_s); |
| 426 |
|
struct vrt_blob b; |
| 427 |
|
VCL_STRING r; |
| 428 |
|
size_t l; |
| 429 |
|
ssize_t len; |
| 430 |
|
|
| 431 |
7280 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 432 |
7280 |
CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC); |
| 433 |
7280 |
CHECK_OBJ_NOTNULL(strings, STRANDS_MAGIC); |
| 434 |
|
|
| 435 |
7280 |
AENC(dec); |
| 436 |
7280 |
AENC(enc); |
| 437 |
|
|
| 438 |
7280 |
if (!check_enc_case(ctx, encs, case_s, enc, kase)) |
| 439 |
0 |
return (NULL); |
| 440 |
|
|
| 441 |
|
/* |
| 442 |
|
* Allocate space for the decoded blob on the stack |
| 443 |
|
* ignoring the limitation imposed by n |
| 444 |
|
*/ |
| 445 |
7280 |
l = decode_l(dec, strings); |
| 446 |
7280 |
if (l == 0) |
| 447 |
0 |
return (""); |
| 448 |
|
|
| 449 |
|
/* XXX: handle stack overflow? */ |
| 450 |
7280 |
char buf[l]; |
| 451 |
|
|
| 452 |
7280 |
if (length <= 0) |
| 453 |
3880 |
length = -1; |
| 454 |
7280 |
errno = 0; |
| 455 |
7280 |
len = func[dec].decode(dec, buf, l, length, strings); |
| 456 |
|
|
| 457 |
7280 |
if (len < 0) { |
| 458 |
800 |
err_decode(ctx, strings->p[0]); |
| 459 |
800 |
return (NULL); |
| 460 |
|
} |
| 461 |
|
|
| 462 |
6480 |
b.magic = VRT_BLOB_MAGIC; |
| 463 |
6480 |
b.len = len; |
| 464 |
6480 |
b.blob = buf; |
| 465 |
|
|
| 466 |
|
/* |
| 467 |
|
* If the encoding and decoding are the same, and the decoding was |
| 468 |
|
* legal, just return the concatenated string. |
| 469 |
|
* For encodings with hex digits, we cannot assume the same result. |
| 470 |
|
* since the call may specify upper- or lower-case that differs |
| 471 |
|
* from the encoded string. |
| 472 |
|
*/ |
| 473 |
6480 |
if (length == -1 && enc == dec && !encodes_hex(enc)) |
| 474 |
|
/* |
| 475 |
|
* Returns NULL and invokes VCL failure on workspace |
| 476 |
|
* overflow. If there is only one string already in the |
| 477 |
|
* workspace, then it is re-used. |
| 478 |
|
*/ |
| 479 |
160 |
return (VRT_STRANDS_string(ctx, strings)); |
| 480 |
|
|
| 481 |
6320 |
r = encode(ctx, enc, kase, &b); |
| 482 |
6320 |
return (r); |
| 483 |
7280 |
} |
| 484 |
|
|
| 485 |
|
VCL_BOOL v_matchproto_(td_blob_same) |
| 486 |
720 |
vmod_same(VRT_CTX, VCL_BLOB b1, VCL_BLOB b2) |
| 487 |
|
{ |
| 488 |
|
|
| 489 |
720 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 490 |
720 |
if (b1 == b2) |
| 491 |
240 |
return (1); |
| 492 |
480 |
if (b1 == NULL || b2 == NULL) |
| 493 |
120 |
return (0); |
| 494 |
360 |
CHECK_OBJ(b1, VRT_BLOB_MAGIC); |
| 495 |
360 |
CHECK_OBJ(b2, VRT_BLOB_MAGIC); |
| 496 |
360 |
return (b1->len == b2->len && b1->blob == b2->blob); |
| 497 |
720 |
} |
| 498 |
|
|
| 499 |
|
VCL_BOOL v_matchproto_(td_blob_equal) |
| 500 |
480 |
vmod_equal(VRT_CTX, VCL_BLOB b1, VCL_BLOB b2) |
| 501 |
|
{ |
| 502 |
|
|
| 503 |
480 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 504 |
480 |
if (b1 == b2) |
| 505 |
120 |
return (1); |
| 506 |
360 |
if (b1 == NULL || b2 == NULL) |
| 507 |
0 |
return (0); |
| 508 |
360 |
CHECK_OBJ(b1, VRT_BLOB_MAGIC); |
| 509 |
360 |
CHECK_OBJ(b2, VRT_BLOB_MAGIC); |
| 510 |
360 |
if (b1->len != b2->len) |
| 511 |
120 |
return (0); |
| 512 |
240 |
if (b1->blob == b2->blob) |
| 513 |
80 |
return (1); |
| 514 |
160 |
if (b1->blob == NULL || b2->blob == NULL) |
| 515 |
0 |
return (0); |
| 516 |
160 |
return (memcmp(b1->blob, b2->blob, b1->len) == 0); |
| 517 |
480 |
} |
| 518 |
|
|
| 519 |
|
VCL_INT v_matchproto_(td_blob_length) |
| 520 |
280 |
vmod_length(VRT_CTX, VCL_BLOB b) |
| 521 |
|
{ |
| 522 |
|
|
| 523 |
280 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 524 |
280 |
if (b == NULL) |
| 525 |
0 |
return (0); |
| 526 |
280 |
CHECK_OBJ(b, VRT_BLOB_MAGIC); |
| 527 |
280 |
return (b->len); |
| 528 |
280 |
} |
| 529 |
|
|
| 530 |
|
VCL_BLOB v_matchproto_(td_blob_sub) |
| 531 |
680 |
vmod_sub(VRT_CTX, VCL_BLOB b, VCL_BYTES n, VCL_BYTES off) |
| 532 |
|
{ |
| 533 |
|
|
| 534 |
680 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 535 |
680 |
assert(n >= 0); |
| 536 |
680 |
assert(off >= 0); |
| 537 |
|
|
| 538 |
680 |
CHECK_OBJ_ORNULL(b, VRT_BLOB_MAGIC); |
| 539 |
680 |
if (b == NULL || b->len == 0 || b->blob == NULL) { |
| 540 |
120 |
ERR(ctx, "blob is empty in blob.sub()"); |
| 541 |
120 |
return (NULL); |
| 542 |
|
} |
| 543 |
|
|
| 544 |
560 |
assert(b->len > 0); |
| 545 |
|
|
| 546 |
|
// XXX check for > SIZE_MAX ? |
| 547 |
560 |
if (off < 0 || n < 0) { |
| 548 |
0 |
ERR(ctx, "size or offset negative in blob.sub()"); |
| 549 |
0 |
return (NULL); |
| 550 |
|
} |
| 551 |
|
|
| 552 |
560 |
if ((size_t)off > b->len || (size_t)n > b->len || |
| 553 |
480 |
(size_t)off + (size_t)n > b->len) { |
| 554 |
160 |
VERR(ctx, "size %jd from offset %jd requires more bytes than " |
| 555 |
|
"blob length %zd in blob.sub()", |
| 556 |
|
(intmax_t)n, (intmax_t)off, b->len); |
| 557 |
160 |
return (NULL); |
| 558 |
|
} |
| 559 |
|
|
| 560 |
800 |
return (VRT_blob(ctx, "blob.sub", |
| 561 |
400 |
(const char *)b->blob + off, n, b->type)); |
| 562 |
680 |
} |