| | varnish-cache/vmod/vmod_blob.c |
0 |
|
/*- |
1 |
|
* Copyright 2015-2017 UPLEX - Nils Goroll Systemoptimierung |
2 |
|
* All rights reserved. |
3 |
|
* |
4 |
669 |
* Authors: Nils Goroll <nils.goroll@uplex.de> |
5 |
1745 |
* Geoffrey Simmons <geoffrey.simmons@uplex.de> |
6 |
1495 |
* |
7 |
941 |
* SPDX-License-Identifier: BSD-2-Clause |
8 |
871 |
* |
9 |
869 |
* Redistribution and use in source and binary forms, with or without |
10 |
585 |
* modification, are permitted provided that the following conditions are met: |
11 |
250 |
* 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 |
1162 |
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 |
669 |
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 |
232 |
decode_l(enum encoding dec, VCL_STRANDS s) |
141 |
|
{ |
142 |
232 |
size_t len = 0; |
143 |
|
|
144 |
232 |
AENC(dec); |
145 |
|
|
146 |
232 |
CHECK_OBJ_NOTNULL(s, STRANDS_MAGIC); |
147 |
510 |
for (int i = 0; i < s->n; i++) |
148 |
526 |
if (s->p[i] != NULL && *s->p[i] != '\0') |
149 |
248 |
len += strlen(s->p[i]); |
150 |
|
|
151 |
232 |
return (func[dec].decode_l(len)); |
152 |
|
} |
153 |
|
|
154 |
|
static void |
155 |
38 |
err_decode(VRT_CTX, const char *enc) |
156 |
|
{ |
157 |
38 |
switch (errno) { |
158 |
|
case EINVAL: |
159 |
34 |
ERRINVAL(ctx, enc); |
160 |
34 |
break; |
161 |
|
case ENOMEM: |
162 |
4 |
ERRNOMEM(ctx, "cannot decode"); |
163 |
4 |
break; |
164 |
|
default: |
165 |
0 |
WRONG("invalid errno"); |
166 |
0 |
} |
167 |
38 |
} |
168 |
|
|
169 |
|
static inline int |
170 |
695 |
encodes_hex(enum encoding enc) |
171 |
|
{ |
172 |
695 |
return (enc == HEX || enc == URL); |
173 |
|
} |
174 |
|
|
175 |
|
/* Require case DEFAULT for all encodings besides HEX and URL. */ |
176 |
|
|
177 |
|
static inline int |
178 |
669 |
check_enc_case(VRT_CTX, VCL_ENUM encs, VCL_ENUM case_s, enum encoding enc, |
179 |
|
enum case_e kase) |
180 |
|
{ |
181 |
669 |
if (!encodes_hex(enc) && kase != DEFAULT) { |
182 |
16 |
VERR(ctx, "case %s is illegal with encoding %s", case_s, encs); |
183 |
16 |
return (0); |
184 |
|
} |
185 |
653 |
return (1); |
186 |
669 |
} |
187 |
|
|
188 |
|
/* Objects */ |
189 |
|
|
190 |
|
VCL_VOID v_matchproto_(td_blob_blob__init) |
191 |
50 |
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 |
50 |
enum encoding dec = parse_encoding(decs); |
196 |
|
void *buf; |
197 |
|
ssize_t len; |
198 |
|
|
199 |
50 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
200 |
50 |
AN(blobp); |
201 |
50 |
AZ(*blobp); |
202 |
50 |
AN(vcl_name); |
203 |
50 |
AENC(dec); |
204 |
50 |
CHECK_OBJ_NOTNULL(strings, STRANDS_MAGIC); |
205 |
|
|
206 |
50 |
ALLOC_OBJ(b, VMOD_BLOB_MAGIC); |
207 |
50 |
AN(b); |
208 |
50 |
*blobp = b; |
209 |
50 |
AZ(pthread_mutex_init(&b->lock, NULL)); |
210 |
|
|
211 |
50 |
b->blob.magic = VRT_BLOB_MAGIC; |
212 |
50 |
b->blob.type = VMOD_BLOB_TYPE; |
213 |
|
|
214 |
50 |
len = decode_l(dec, strings); |
215 |
50 |
if (len == 0) |
216 |
8 |
return; |
217 |
|
|
218 |
42 |
assert(len > 0); |
219 |
|
|
220 |
42 |
buf = malloc(len); |
221 |
42 |
if (buf == NULL) { |
222 |
0 |
VERRNOMEM(ctx, "cannot create blob %s", vcl_name); |
223 |
0 |
return; |
224 |
|
} |
225 |
|
|
226 |
42 |
errno = 0; |
227 |
42 |
len = func[dec].decode(dec, buf, len, -1, strings); |
228 |
|
|
229 |
42 |
if (len == -1) { |
230 |
8 |
assert(errno == EINVAL); |
231 |
8 |
free(buf); |
232 |
8 |
VERR(ctx, "cannot create blob %s, illegal encoding beginning " |
233 |
|
"with \"%s\"", vcl_name, strings->p[0]); |
234 |
8 |
return; |
235 |
|
} |
236 |
34 |
if (len == 0) { |
237 |
0 |
free(buf); |
238 |
0 |
memcpy(&b->blob, vrt_null_blob, sizeof b->blob); |
239 |
0 |
return; |
240 |
|
} |
241 |
34 |
b->blob.len = len; |
242 |
34 |
b->blob.blob = b->freeptr = buf; |
243 |
50 |
} |
244 |
|
|
245 |
|
VCL_BLOB v_matchproto_(td_blob_blob_get) |
246 |
107 |
vmod_blob_get(VRT_CTX, struct vmod_blob_blob *b) |
247 |
|
{ |
248 |
107 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
249 |
107 |
CHECK_OBJ_NOTNULL(b, VMOD_BLOB_MAGIC); |
250 |
107 |
CHECK_OBJ(&b->blob, VRT_BLOB_MAGIC); |
251 |
107 |
return (&b->blob); |
252 |
|
} |
253 |
|
|
254 |
|
VCL_STRING v_matchproto_(td_blob_blob_encode) |
255 |
177 |
vmod_blob_encode(VRT_CTX, struct vmod_blob_blob *b, VCL_ENUM encs, |
256 |
|
VCL_ENUM case_s) |
257 |
|
{ |
258 |
177 |
enum encoding enc = parse_encoding(encs); |
259 |
177 |
AENC(enc); |
260 |
177 |
enum case_e kase = parse_case(case_s); |
261 |
|
|
262 |
177 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
263 |
177 |
CHECK_OBJ_NOTNULL(b, VMOD_BLOB_MAGIC); |
264 |
177 |
CHECK_OBJ(&b->blob, VRT_BLOB_MAGIC); |
265 |
|
|
266 |
177 |
if (!check_enc_case(ctx, encs, case_s, enc, kase)) |
267 |
8 |
return (NULL); |
268 |
169 |
if (b->blob.len == 0) |
269 |
20 |
return (""); |
270 |
149 |
if (kase == DEFAULT) |
271 |
91 |
kase = LOWER; |
272 |
|
|
273 |
149 |
if (b->encoding[enc][kase] == NULL) { |
274 |
61 |
PTOK(pthread_mutex_lock(&b->lock)); |
275 |
61 |
if (b->encoding[enc][kase] == NULL) { |
276 |
61 |
ssize_t len = func[enc].encode_l(b->blob.len); |
277 |
|
|
278 |
61 |
assert(len >= 0); |
279 |
61 |
if (len == 0) |
280 |
0 |
b->encoding[enc][kase] = empty; |
281 |
|
else { |
282 |
61 |
b->encoding[enc][kase] = malloc(len); |
283 |
61 |
if (b->encoding[enc][kase] == NULL) |
284 |
0 |
ERRNOMEM(ctx, "cannot encode"); |
285 |
|
else { |
286 |
61 |
char *s = b->encoding[enc][kase]; |
287 |
61 |
len = |
288 |
122 |
func[enc].encode( |
289 |
61 |
enc, kase, s, len, |
290 |
61 |
b->blob.blob, |
291 |
61 |
b->blob.len); |
292 |
61 |
assert(len >= 0); |
293 |
61 |
if (len == 0) { |
294 |
0 |
free(s); |
295 |
0 |
b->encoding[enc][kase] = empty; |
296 |
0 |
} |
297 |
|
else |
298 |
61 |
s[len] = '\0'; |
299 |
|
} |
300 |
|
} |
301 |
61 |
} |
302 |
61 |
PTOK(pthread_mutex_unlock(&b->lock)); |
303 |
61 |
} |
304 |
149 |
return (b->encoding[enc][kase]); |
305 |
177 |
} |
306 |
|
|
307 |
|
VCL_VOID v_matchproto_(td_blob_blob__fini) |
308 |
25 |
vmod_blob__fini(struct vmod_blob_blob **blobp) |
309 |
|
{ |
310 |
|
struct vmod_blob_blob *b; |
311 |
|
char *s; |
312 |
|
int i, j; |
313 |
|
|
314 |
25 |
TAKE_OBJ_NOTNULL(b, blobp, VMOD_BLOB_MAGIC); |
315 |
25 |
CHECK_OBJ(&b->blob, VRT_BLOB_MAGIC); |
316 |
|
|
317 |
25 |
if (b->freeptr != NULL) { |
318 |
14 |
free(b->freeptr); |
319 |
14 |
b->blob.blob = NULL; |
320 |
14 |
} |
321 |
|
|
322 |
225 |
for (i = 0; i < __MAX_ENCODING; i++) |
323 |
600 |
for (j = 0; j < 2; j++) { |
324 |
400 |
s = b->encoding[i][j]; |
325 |
400 |
if (s != NULL && s != empty) { |
326 |
20 |
free(s); |
327 |
20 |
b->encoding[i][j] = NULL; |
328 |
20 |
} |
329 |
600 |
} |
330 |
|
|
331 |
25 |
PTOK(pthread_mutex_destroy(&b->lock)); |
332 |
25 |
FREE_OBJ(b); |
333 |
25 |
} |
334 |
|
|
335 |
|
/* Functions */ |
336 |
|
|
337 |
|
VCL_BLOB v_matchproto_(td_blob_decode) |
338 |
261 |
vmod_decode(VRT_CTX, VCL_ENUM decs, VCL_INT length, VCL_STRANDS strings) |
339 |
|
{ |
340 |
261 |
enum encoding dec = parse_encoding(decs); |
341 |
|
char *buf; |
342 |
|
ssize_t len; |
343 |
|
unsigned space; |
344 |
|
|
345 |
261 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
346 |
261 |
AENC(dec); |
347 |
261 |
CHECK_OBJ_NOTNULL(strings, STRANDS_MAGIC); |
348 |
261 |
CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC); |
349 |
|
|
350 |
261 |
space = WS_ReserveAll(ctx->ws); |
351 |
261 |
buf = WS_Reservation(ctx->ws); |
352 |
|
|
353 |
261 |
if (length <= 0) |
354 |
180 |
length = -1; |
355 |
261 |
errno = 0; |
356 |
261 |
len = func[dec].decode(dec, buf, space, length, strings); |
357 |
|
|
358 |
261 |
if (len == -1) { |
359 |
18 |
err_decode(ctx, strings->p[0]); |
360 |
18 |
WS_Release(ctx->ws, 0); |
361 |
18 |
return (NULL); |
362 |
|
} |
363 |
243 |
if (len == 0) { |
364 |
42 |
WS_Release(ctx->ws, 0); |
365 |
42 |
return (vrt_null_blob); |
366 |
|
} |
367 |
201 |
WS_Release(ctx->ws, len); |
368 |
|
|
369 |
201 |
assert(len > 0); |
370 |
|
|
371 |
201 |
return (VRT_blob(ctx, "blob.decode", buf, len, VMOD_BLOB_TYPE)); |
372 |
261 |
} |
373 |
|
|
374 |
|
static VCL_STRING |
375 |
460 |
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 |
460 |
AENC(enc); |
382 |
|
|
383 |
460 |
if (b == NULL) |
384 |
27 |
return (NULL); |
385 |
|
|
386 |
433 |
CHECK_OBJ(b, VRT_BLOB_MAGIC); |
387 |
433 |
CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC); |
388 |
433 |
space = WS_ReserveAll(ctx->ws); |
389 |
433 |
buf = WS_Reservation(ctx->ws); |
390 |
|
|
391 |
433 |
len = func[enc].encode(enc, kase, buf, space, b->blob, b->len); |
392 |
|
|
393 |
433 |
if (len == -1) { |
394 |
5 |
ERRNOMEM(ctx, "cannot encode"); |
395 |
5 |
WS_Release(ctx->ws, 0); |
396 |
5 |
return (NULL); |
397 |
|
} |
398 |
428 |
if (len == 0) { |
399 |
36 |
WS_Release(ctx->ws, 0); |
400 |
36 |
return (""); |
401 |
|
} |
402 |
392 |
buf[len] = '\0'; |
403 |
392 |
WS_Release(ctx->ws, len + 1); |
404 |
392 |
return (buf); |
405 |
460 |
} |
406 |
|
|
407 |
|
VCL_STRING v_matchproto_(td_blob_encode) |
408 |
310 |
vmod_encode(VRT_CTX, VCL_ENUM encs, VCL_ENUM case_s, VCL_BLOB b) |
409 |
|
{ |
410 |
310 |
enum encoding enc = parse_encoding(encs); |
411 |
310 |
enum case_e kase = parse_case(case_s); |
412 |
|
|
413 |
310 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
414 |
310 |
if (!check_enc_case(ctx, encs, case_s, enc, kase)) |
415 |
8 |
return (NULL); |
416 |
302 |
return (encode(ctx, enc, kase, b)); |
417 |
310 |
} |
418 |
|
|
419 |
|
VCL_STRING v_matchproto_(td_blob_transcode) |
420 |
182 |
vmod_transcode(VRT_CTX, VCL_ENUM decs, VCL_ENUM encs, VCL_ENUM case_s, |
421 |
|
VCL_INT length, VCL_STRANDS strings) |
422 |
|
{ |
423 |
182 |
enum encoding dec = parse_encoding(decs); |
424 |
182 |
enum encoding enc = parse_encoding(encs); |
425 |
182 |
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 |
182 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
432 |
182 |
CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC); |
433 |
182 |
CHECK_OBJ_NOTNULL(strings, STRANDS_MAGIC); |
434 |
|
|
435 |
182 |
AENC(dec); |
436 |
182 |
AENC(enc); |
437 |
|
|
438 |
182 |
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 |
182 |
l = decode_l(dec, strings); |
446 |
182 |
if (l == 0) |
447 |
0 |
return (""); |
448 |
|
|
449 |
|
/* XXX: handle stack overflow? */ |
450 |
182 |
char buf[l]; |
451 |
|
|
452 |
182 |
if (length <= 0) |
453 |
97 |
length = -1; |
454 |
182 |
errno = 0; |
455 |
182 |
len = func[dec].decode(dec, buf, l, length, strings); |
456 |
|
|
457 |
182 |
if (len < 0) { |
458 |
20 |
err_decode(ctx, strings->p[0]); |
459 |
20 |
return (NULL); |
460 |
|
} |
461 |
|
|
462 |
162 |
b.magic = VRT_BLOB_MAGIC; |
463 |
162 |
b.len = len; |
464 |
162 |
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 |
162 |
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 |
4 |
return (VRT_STRANDS_string(ctx, strings)); |
480 |
|
|
481 |
158 |
r = encode(ctx, enc, kase, &b); |
482 |
158 |
return (r); |
483 |
182 |
} |
484 |
|
|
485 |
|
VCL_BOOL v_matchproto_(td_blob_same) |
486 |
18 |
vmod_same(VRT_CTX, VCL_BLOB b1, VCL_BLOB b2) |
487 |
|
{ |
488 |
|
|
489 |
18 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
490 |
18 |
if (b1 == b2) |
491 |
6 |
return (1); |
492 |
12 |
if (b1 == NULL || b2 == NULL) |
493 |
3 |
return (0); |
494 |
9 |
CHECK_OBJ(b1, VRT_BLOB_MAGIC); |
495 |
9 |
CHECK_OBJ(b2, VRT_BLOB_MAGIC); |
496 |
9 |
return (b1->len == b2->len && b1->blob == b2->blob); |
497 |
18 |
} |
498 |
|
|
499 |
|
VCL_BOOL v_matchproto_(td_blob_equal) |
500 |
12 |
vmod_equal(VRT_CTX, VCL_BLOB b1, VCL_BLOB b2) |
501 |
|
{ |
502 |
|
|
503 |
12 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
504 |
12 |
if (b1 == b2) |
505 |
3 |
return (1); |
506 |
9 |
if (b1 == NULL || b2 == NULL) |
507 |
0 |
return (0); |
508 |
9 |
CHECK_OBJ(b1, VRT_BLOB_MAGIC); |
509 |
9 |
CHECK_OBJ(b2, VRT_BLOB_MAGIC); |
510 |
9 |
if (b1->len != b2->len) |
511 |
3 |
return (0); |
512 |
6 |
if (b1->blob == b2->blob) |
513 |
2 |
return (1); |
514 |
4 |
if (b1->blob == NULL || b2->blob == NULL) |
515 |
0 |
return (0); |
516 |
4 |
return (memcmp(b1->blob, b2->blob, b1->len) == 0); |
517 |
12 |
} |
518 |
|
|
519 |
|
VCL_INT v_matchproto_(td_blob_length) |
520 |
7 |
vmod_length(VRT_CTX, VCL_BLOB b) |
521 |
|
{ |
522 |
|
|
523 |
7 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
524 |
7 |
if (b == NULL) |
525 |
0 |
return (0); |
526 |
7 |
CHECK_OBJ(b, VRT_BLOB_MAGIC); |
527 |
7 |
return (b->len); |
528 |
7 |
} |
529 |
|
|
530 |
|
VCL_BLOB v_matchproto_(td_blob_sub) |
531 |
17 |
vmod_sub(VRT_CTX, VCL_BLOB b, VCL_BYTES n, VCL_BYTES off) |
532 |
|
{ |
533 |
|
|
534 |
17 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
535 |
17 |
assert(n >= 0); |
536 |
17 |
assert(off >= 0); |
537 |
|
|
538 |
17 |
CHECK_OBJ_ORNULL(b, VRT_BLOB_MAGIC); |
539 |
17 |
if (b == NULL || b->len == 0 || b->blob == NULL) { |
540 |
3 |
ERR(ctx, "blob is empty in blob.sub()"); |
541 |
3 |
return (NULL); |
542 |
|
} |
543 |
|
|
544 |
14 |
assert(b->len > 0); |
545 |
|
|
546 |
|
// XXX check for > SIZE_MAX ? |
547 |
14 |
if (off < 0 || n < 0) { |
548 |
0 |
ERR(ctx, "size or offset negative in blob.sub()"); |
549 |
0 |
return (NULL); |
550 |
|
} |
551 |
|
|
552 |
14 |
if ((size_t)off > b->len || (size_t)n > b->len || |
553 |
12 |
(size_t)off + (size_t)n > b->len) { |
554 |
4 |
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 |
4 |
return (NULL); |
558 |
|
} |
559 |
|
|
560 |
20 |
return (VRT_blob(ctx, "blob.sub", |
561 |
10 |
(const char *)b->blob + off, n, b->type)); |
562 |
17 |
} |