| | varnish-cache/vmod/vmod_blob.c |
0 |
|
/*- |
1 |
|
* Copyright 2015-2017 UPLEX - Nils Goroll Systemoptimierung |
2 |
|
* All rights reserved. |
3 |
|
* |
4 |
26758 |
* Authors: Nils Goroll <nils.goroll@uplex.de> |
5 |
69716 |
* Geoffrey Simmons <geoffrey.simmons@uplex.de> |
6 |
59716 |
* |
7 |
37558 |
* SPDX-License-Identifier: BSD-2-Clause |
8 |
34758 |
* |
9 |
34678 |
* 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 |
46398 |
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 |
26758 |
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 |
20400 |
for (int i = 0; i < s->n; i++) |
147 |
21040 |
if (s->p[i] != NULL && *s->p[i] != '\0') |
148 |
9920 |
len += strlen(s->p[i]); |
149 |
|
|
150 |
9280 |
return (func[dec].decode_l(len)); |
151 |
|
} |
152 |
|
|
153 |
|
static void |
154 |
1520 |
err_decode(VRT_CTX, const char *enc) |
155 |
|
{ |
156 |
1520 |
switch (errno) { |
157 |
|
case EINVAL: |
158 |
1360 |
ERRINVAL(ctx, enc); |
159 |
1360 |
break; |
160 |
|
case ENOMEM: |
161 |
160 |
ERRNOMEM(ctx, "cannot decode"); |
162 |
160 |
break; |
163 |
|
default: |
164 |
0 |
WRONG("invalid errno"); |
165 |
0 |
} |
166 |
1520 |
} |
167 |
|
|
168 |
|
static inline int |
169 |
27799 |
encodes_hex(enum encoding enc) |
170 |
|
{ |
171 |
27799 |
return (enc == HEX || enc == URL); |
172 |
|
} |
173 |
|
|
174 |
|
/* Require case DEFAULT for all encodings besides HEX and URL. */ |
175 |
|
|
176 |
|
static inline int |
177 |
26758 |
check_enc_case(VRT_CTX, VCL_ENUM encs, VCL_ENUM case_s, enum encoding enc, |
178 |
|
enum case_e kase) |
179 |
|
{ |
180 |
26758 |
if (!encodes_hex(enc) && kase != DEFAULT) { |
181 |
640 |
VERR(ctx, "case %s is illegal with encoding %s", case_s, encs); |
182 |
640 |
return (0); |
183 |
|
} |
184 |
26118 |
return (1); |
185 |
26758 |
} |
186 |
|
|
187 |
|
/* Objects */ |
188 |
|
|
189 |
|
VCL_VOID v_matchproto_(td_blob_blob__init) |
190 |
2000 |
vmod_blob__init(VRT_CTX, struct vmod_blob_blob **blobp, const char *vcl_name, |
191 |
|
VCL_ENUM decs, VCL_STRANDS strings) |
192 |
|
{ |
193 |
|
struct vmod_blob_blob *b; |
194 |
2000 |
enum encoding dec = parse_encoding(decs); |
195 |
|
void *buf; |
196 |
|
ssize_t len; |
197 |
|
|
198 |
2000 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
199 |
2000 |
AN(blobp); |
200 |
2000 |
AZ(*blobp); |
201 |
2000 |
AN(vcl_name); |
202 |
2000 |
AENC(dec); |
203 |
2000 |
AN(strings); |
204 |
|
|
205 |
2000 |
ALLOC_OBJ(b, VMOD_BLOB_MAGIC); |
206 |
2000 |
AN(b); |
207 |
2000 |
*blobp = b; |
208 |
2000 |
AZ(pthread_mutex_init(&b->lock, NULL)); |
209 |
|
|
210 |
2000 |
b->blob.type = VMOD_BLOB_TYPE; |
211 |
|
|
212 |
2000 |
len = decode_l(dec, strings); |
213 |
2000 |
if (len == 0) |
214 |
320 |
return; |
215 |
|
|
216 |
1680 |
assert(len > 0); |
217 |
|
|
218 |
1680 |
buf = malloc(len); |
219 |
1680 |
if (buf == NULL) { |
220 |
0 |
VERRNOMEM(ctx, "cannot create blob %s", vcl_name); |
221 |
0 |
return; |
222 |
|
} |
223 |
|
|
224 |
1680 |
errno = 0; |
225 |
1680 |
len = func[dec].decode(dec, buf, len, -1, strings); |
226 |
|
|
227 |
1680 |
if (len == -1) { |
228 |
320 |
assert(errno == EINVAL); |
229 |
320 |
free(buf); |
230 |
320 |
VERR(ctx, "cannot create blob %s, illegal encoding beginning " |
231 |
|
"with \"%s\"", vcl_name, strings->p[0]); |
232 |
320 |
return; |
233 |
|
} |
234 |
1360 |
if (len == 0) { |
235 |
0 |
free(buf); |
236 |
0 |
memcpy(&b->blob, vrt_null_blob, sizeof b->blob); |
237 |
0 |
return; |
238 |
|
} |
239 |
1360 |
b->blob.len = len; |
240 |
1360 |
b->blob.blob = b->freeptr = buf; |
241 |
2000 |
} |
242 |
|
|
243 |
|
VCL_BLOB v_matchproto_(td_blob_blob_get) |
244 |
4280 |
vmod_blob_get(VRT_CTX, struct vmod_blob_blob *b) |
245 |
|
{ |
246 |
4280 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
247 |
4280 |
CHECK_OBJ_NOTNULL(b, VMOD_BLOB_MAGIC); |
248 |
4280 |
return (&b->blob); |
249 |
|
} |
250 |
|
|
251 |
|
VCL_STRING v_matchproto_(td_blob_blob_encode) |
252 |
7080 |
vmod_blob_encode(VRT_CTX, struct vmod_blob_blob *b, VCL_ENUM encs, |
253 |
|
VCL_ENUM case_s) |
254 |
|
{ |
255 |
7080 |
enum encoding enc = parse_encoding(encs); |
256 |
7080 |
AENC(enc); |
257 |
7080 |
enum case_e kase = parse_case(case_s); |
258 |
|
|
259 |
7080 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
260 |
7080 |
CHECK_OBJ_NOTNULL(b, VMOD_BLOB_MAGIC); |
261 |
|
|
262 |
7080 |
if (!check_enc_case(ctx, encs, case_s, enc, kase)) |
263 |
320 |
return (NULL); |
264 |
6760 |
if (b->blob.len == 0) |
265 |
800 |
return (""); |
266 |
5960 |
if (kase == DEFAULT) |
267 |
3640 |
kase = LOWER; |
268 |
|
|
269 |
5960 |
if (b->encoding[enc][kase] == NULL) { |
270 |
2440 |
PTOK(pthread_mutex_lock(&b->lock)); |
271 |
2440 |
if (b->encoding[enc][kase] == NULL) { |
272 |
2440 |
ssize_t len = func[enc].encode_l(b->blob.len); |
273 |
|
|
274 |
2440 |
assert(len >= 0); |
275 |
2440 |
if (len == 0) |
276 |
0 |
b->encoding[enc][kase] = empty; |
277 |
|
else { |
278 |
2440 |
b->encoding[enc][kase] = malloc(len); |
279 |
2440 |
if (b->encoding[enc][kase] == NULL) |
280 |
0 |
ERRNOMEM(ctx, "cannot encode"); |
281 |
|
else { |
282 |
2440 |
char *s = b->encoding[enc][kase]; |
283 |
2440 |
len = |
284 |
4880 |
func[enc].encode( |
285 |
2440 |
enc, kase, s, len, |
286 |
2440 |
b->blob.blob, |
287 |
2440 |
b->blob.len); |
288 |
2440 |
assert(len >= 0); |
289 |
2440 |
if (len == 0) { |
290 |
0 |
free(s); |
291 |
0 |
b->encoding[enc][kase] = empty; |
292 |
0 |
} |
293 |
|
else |
294 |
2440 |
s[len] = '\0'; |
295 |
|
} |
296 |
|
} |
297 |
2440 |
} |
298 |
2440 |
PTOK(pthread_mutex_unlock(&b->lock)); |
299 |
2440 |
} |
300 |
5960 |
return (b->encoding[enc][kase]); |
301 |
7080 |
} |
302 |
|
|
303 |
|
VCL_VOID v_matchproto_(td_blob_blob__fini) |
304 |
1000 |
vmod_blob__fini(struct vmod_blob_blob **blobp) |
305 |
|
{ |
306 |
|
struct vmod_blob_blob *b; |
307 |
|
char *s; |
308 |
|
int i, j; |
309 |
|
|
310 |
1000 |
TAKE_OBJ_NOTNULL(b, blobp, VMOD_BLOB_MAGIC); |
311 |
|
|
312 |
1000 |
if (b->freeptr != NULL) { |
313 |
560 |
free(b->freeptr); |
314 |
560 |
b->blob.blob = NULL; |
315 |
560 |
} |
316 |
|
|
317 |
9000 |
for (i = 0; i < __MAX_ENCODING; i++) |
318 |
24000 |
for (j = 0; j < 2; j++) { |
319 |
16000 |
s = b->encoding[i][j]; |
320 |
16000 |
if (s != NULL && s != empty) { |
321 |
800 |
free(s); |
322 |
800 |
b->encoding[i][j] = NULL; |
323 |
800 |
} |
324 |
24000 |
} |
325 |
|
|
326 |
1000 |
PTOK(pthread_mutex_destroy(&b->lock)); |
327 |
1000 |
FREE_OBJ(b); |
328 |
1000 |
} |
329 |
|
|
330 |
|
/* Functions */ |
331 |
|
|
332 |
|
VCL_BLOB v_matchproto_(td_blob_decode) |
333 |
10360 |
vmod_decode(VRT_CTX, VCL_ENUM decs, VCL_INT length, VCL_STRANDS strings) |
334 |
|
{ |
335 |
10360 |
enum encoding dec = parse_encoding(decs); |
336 |
|
char *buf; |
337 |
|
ssize_t len; |
338 |
|
unsigned space; |
339 |
|
|
340 |
10360 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
341 |
10360 |
AENC(dec); |
342 |
10360 |
AN(strings); |
343 |
10360 |
CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC); |
344 |
|
|
345 |
10360 |
space = WS_ReserveAll(ctx->ws); |
346 |
10360 |
buf = WS_Reservation(ctx->ws); |
347 |
|
|
348 |
10360 |
if (length <= 0) |
349 |
7120 |
length = -1; |
350 |
10360 |
errno = 0; |
351 |
10360 |
len = func[dec].decode(dec, buf, space, length, strings); |
352 |
|
|
353 |
10360 |
if (len == -1) { |
354 |
720 |
err_decode(ctx, strings->p[0]); |
355 |
720 |
WS_Release(ctx->ws, 0); |
356 |
720 |
return (NULL); |
357 |
|
} |
358 |
9640 |
if (len == 0) { |
359 |
1680 |
WS_Release(ctx->ws, 0); |
360 |
1680 |
return (vrt_null_blob); |
361 |
|
} |
362 |
7960 |
WS_Release(ctx->ws, len); |
363 |
|
|
364 |
7960 |
assert(len > 0); |
365 |
|
|
366 |
7960 |
return (VRT_blob(ctx, "blob.decode", buf, len, VMOD_BLOB_TYPE)); |
367 |
10360 |
} |
368 |
|
|
369 |
|
static VCL_STRING |
370 |
18400 |
encode(VRT_CTX, enum encoding enc, enum case_e kase, VCL_BLOB b) |
371 |
|
{ |
372 |
|
ssize_t len; |
373 |
|
char *buf; |
374 |
|
unsigned space; |
375 |
|
|
376 |
18400 |
AENC(enc); |
377 |
|
|
378 |
18400 |
if (b == NULL) |
379 |
1080 |
return (NULL); |
380 |
|
|
381 |
17320 |
CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC); |
382 |
17320 |
space = WS_ReserveAll(ctx->ws); |
383 |
17320 |
buf = WS_Reservation(ctx->ws); |
384 |
|
|
385 |
17320 |
len = func[enc].encode(enc, kase, buf, space, b->blob, b->len); |
386 |
|
|
387 |
17320 |
if (len == -1) { |
388 |
200 |
ERRNOMEM(ctx, "cannot encode"); |
389 |
200 |
WS_Release(ctx->ws, 0); |
390 |
200 |
return (NULL); |
391 |
|
} |
392 |
17120 |
if (len == 0) { |
393 |
1440 |
WS_Release(ctx->ws, 0); |
394 |
1440 |
return (""); |
395 |
|
} |
396 |
15680 |
buf[len] = '\0'; |
397 |
15680 |
WS_Release(ctx->ws, len + 1); |
398 |
15680 |
return (buf); |
399 |
18400 |
} |
400 |
|
|
401 |
|
VCL_STRING v_matchproto_(td_blob_encode) |
402 |
12398 |
vmod_encode(VRT_CTX, VCL_ENUM encs, VCL_ENUM case_s, VCL_BLOB b) |
403 |
|
{ |
404 |
12398 |
enum encoding enc = parse_encoding(encs); |
405 |
12398 |
enum case_e kase = parse_case(case_s); |
406 |
|
|
407 |
12398 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
408 |
12398 |
if (!check_enc_case(ctx, encs, case_s, enc, kase)) |
409 |
320 |
return (NULL); |
410 |
12078 |
return (encode(ctx, enc, kase, b)); |
411 |
12398 |
} |
412 |
|
|
413 |
|
VCL_STRING v_matchproto_(td_blob_transcode) |
414 |
7280 |
vmod_transcode(VRT_CTX, VCL_ENUM decs, VCL_ENUM encs, VCL_ENUM case_s, |
415 |
|
VCL_INT length, VCL_STRANDS strings) |
416 |
|
{ |
417 |
7280 |
enum encoding dec = parse_encoding(decs); |
418 |
7280 |
enum encoding enc = parse_encoding(encs); |
419 |
7280 |
enum case_e kase = parse_case(case_s); |
420 |
|
struct vrt_blob b; |
421 |
|
VCL_STRING r; |
422 |
|
size_t l; |
423 |
|
ssize_t len; |
424 |
|
|
425 |
7280 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
426 |
7280 |
CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC); |
427 |
7280 |
AN(strings); |
428 |
|
|
429 |
7280 |
AENC(dec); |
430 |
7280 |
AENC(enc); |
431 |
|
|
432 |
7280 |
if (!check_enc_case(ctx, encs, case_s, enc, kase)) |
433 |
0 |
return (NULL); |
434 |
|
|
435 |
|
/* |
436 |
|
* Allocate space for the decoded blob on the stack |
437 |
|
* ignoring the limitation imposed by n |
438 |
|
*/ |
439 |
7280 |
l = decode_l(dec, strings); |
440 |
7280 |
if (l == 0) |
441 |
0 |
return (""); |
442 |
|
|
443 |
|
/* XXX: handle stack overflow? */ |
444 |
7280 |
char buf[l]; |
445 |
|
|
446 |
7280 |
if (length <= 0) |
447 |
3880 |
length = -1; |
448 |
7280 |
errno = 0; |
449 |
7280 |
len = func[dec].decode(dec, buf, l, length, strings); |
450 |
|
|
451 |
7280 |
if (len < 0) { |
452 |
800 |
err_decode(ctx, strings->p[0]); |
453 |
800 |
return (NULL); |
454 |
|
} |
455 |
|
|
456 |
6480 |
b.len = len; |
457 |
6480 |
b.blob = buf; |
458 |
|
|
459 |
|
/* |
460 |
|
* If the encoding and decoding are the same, and the decoding was |
461 |
|
* legal, just return the concatenated string. |
462 |
|
* For encodings with hex digits, we cannot assume the same result. |
463 |
|
* since the call may specify upper- or lower-case that differs |
464 |
|
* from the encoded string. |
465 |
|
*/ |
466 |
6480 |
if (length == -1 && enc == dec && !encodes_hex(enc)) |
467 |
|
/* |
468 |
|
* Returns NULL and invokes VCL failure on workspace |
469 |
|
* overflow. If there is only one string already in the |
470 |
|
* workspace, then it is re-used. |
471 |
|
*/ |
472 |
160 |
return (VRT_STRANDS_string(ctx, strings)); |
473 |
|
|
474 |
6320 |
r = encode(ctx, enc, kase, &b); |
475 |
6320 |
return (r); |
476 |
7280 |
} |
477 |
|
|
478 |
|
VCL_BOOL v_matchproto_(td_blob_same) |
479 |
720 |
vmod_same(VRT_CTX, VCL_BLOB b1, VCL_BLOB b2) |
480 |
|
{ |
481 |
|
|
482 |
720 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
483 |
720 |
if (b1 == b2) |
484 |
240 |
return (1); |
485 |
480 |
if (b1 == NULL || b2 == NULL) |
486 |
120 |
return (0); |
487 |
360 |
return (b1->len == b2->len && b1->blob == b2->blob); |
488 |
720 |
} |
489 |
|
|
490 |
|
VCL_BOOL v_matchproto_(td_blob_equal) |
491 |
480 |
vmod_equal(VRT_CTX, VCL_BLOB b1, VCL_BLOB b2) |
492 |
|
{ |
493 |
|
|
494 |
480 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
495 |
480 |
if (b1 == b2) |
496 |
120 |
return (1); |
497 |
360 |
if (b1 == NULL || b2 == NULL) |
498 |
0 |
return (0); |
499 |
360 |
if (b1->len != b2->len) |
500 |
120 |
return (0); |
501 |
240 |
if (b1->blob == b2->blob) |
502 |
80 |
return (1); |
503 |
160 |
if (b1->blob == NULL || b2->blob == NULL) |
504 |
0 |
return (0); |
505 |
160 |
return (memcmp(b1->blob, b2->blob, b1->len) == 0); |
506 |
480 |
} |
507 |
|
|
508 |
|
VCL_INT v_matchproto_(td_blob_length) |
509 |
280 |
vmod_length(VRT_CTX, VCL_BLOB b) |
510 |
|
{ |
511 |
|
|
512 |
280 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
513 |
280 |
if (b == NULL) |
514 |
0 |
return (0); |
515 |
280 |
return (b->len); |
516 |
280 |
} |
517 |
|
|
518 |
|
VCL_BLOB v_matchproto_(td_blob_sub) |
519 |
680 |
vmod_sub(VRT_CTX, VCL_BLOB b, VCL_BYTES n, VCL_BYTES off) |
520 |
|
{ |
521 |
|
|
522 |
680 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
523 |
680 |
assert(n >= 0); |
524 |
680 |
assert(off >= 0); |
525 |
|
|
526 |
680 |
if (b == NULL || b->len == 0 || b->blob == NULL) { |
527 |
120 |
ERR(ctx, "blob is empty in blob.sub()"); |
528 |
120 |
return (NULL); |
529 |
|
} |
530 |
|
|
531 |
560 |
assert(b->len > 0); |
532 |
|
|
533 |
|
// XXX check for > SIZE_MAX ? |
534 |
560 |
if (off < 0 || n < 0) { |
535 |
0 |
ERR(ctx, "size or offset negative in blob.sub()"); |
536 |
0 |
return (NULL); |
537 |
|
} |
538 |
|
|
539 |
560 |
if ((size_t)off > b->len || (size_t)n > b->len || |
540 |
480 |
(size_t)off + (size_t)n > b->len) { |
541 |
160 |
VERR(ctx, "size %jd from offset %jd requires more bytes than " |
542 |
|
"blob length %zd in blob.sub()", |
543 |
|
(intmax_t)n, (intmax_t)off, b->len); |
544 |
160 |
return (NULL); |
545 |
|
} |
546 |
|
|
547 |
800 |
return (VRT_blob(ctx, "blob.sub", |
548 |
400 |
(const char *)b->blob + off, n, b->type)); |
549 |
680 |
} |