| | varnish-cache/vmod/vmod_vtc.c |
0 |
|
/*- |
1 |
|
* Copyright (c) 2012-2017 Varnish Software AS |
2 |
|
* All rights reserved. |
3 |
|
* |
4 |
|
* Author: Poul-Henning Kamp <phk@FreeBSD.org> |
5 |
|
* Author: Dridi Boukelmoune <dridi.boukelmoune@gmail.com> |
6 |
|
* |
7 |
|
* SPDX-License-Identifier: BSD-2-Clause |
8 |
|
* |
9 |
|
* Redistribution and use in source and binary forms, with or without |
10 |
|
* modification, are permitted provided that the following conditions |
11 |
|
* are met: |
12 |
|
* 1. Redistributions of source code must retain the above copyright |
13 |
|
* notice, this list of conditions and the following disclaimer. |
14 |
|
* 2. Redistributions in binary form must reproduce the above copyright |
15 |
|
* notice, this list of conditions and the following disclaimer in the |
16 |
|
* documentation and/or other materials provided with the distribution. |
17 |
|
* |
18 |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
19 |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
20 |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
21 |
|
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
22 |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
23 |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
24 |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
25 |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
26 |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
27 |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
28 |
|
* SUCH DAMAGE. |
29 |
|
*/ |
30 |
|
|
31 |
|
#include "config.h" |
32 |
|
|
33 |
|
#include <stdlib.h> |
34 |
|
#include <stdio.h> |
35 |
|
#include <string.h> |
36 |
|
#include <unistd.h> |
37 |
|
|
38 |
|
#include "cache/cache.h" |
39 |
|
|
40 |
|
#include "vsb.h" |
41 |
|
#include "vtcp.h" |
42 |
|
#include "vtim.h" |
43 |
|
|
44 |
|
#include "vcc_vtc_if.h" |
45 |
|
|
46 |
|
VCL_VOID v_matchproto_(td_vtc_barrier_sync) |
47 |
2351 |
vmod_barrier_sync(VRT_CTX, VCL_STRING addr, VCL_DURATION tmo) |
48 |
|
{ |
49 |
|
const char *err; |
50 |
|
char buf[32]; |
51 |
|
int sock, i; |
52 |
|
ssize_t sz; |
53 |
|
|
54 |
2351 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
55 |
2351 |
AN(addr); |
56 |
2351 |
AN(*addr); |
57 |
2351 |
assert(tmo >= 0.0); |
58 |
|
|
59 |
2351 |
if (ctx->vsl != NULL) |
60 |
2351 |
VSLb(ctx->vsl, SLT_Debug, "barrier_sync(\"%s\")", addr); |
61 |
|
else |
62 |
0 |
VSL(SLT_Debug, NO_VXID, "barrier_sync(\"%s\")", addr); |
63 |
|
|
64 |
2351 |
sock = VTCP_open(addr, NULL, 0., &err); |
65 |
2351 |
if (sock < 0) { |
66 |
0 |
VRT_fail(ctx, "Barrier connection failed: %s", err); |
67 |
0 |
return; |
68 |
|
} |
69 |
|
|
70 |
2351 |
sz = VTCP_read(sock, buf, sizeof buf, tmo); |
71 |
2351 |
i = errno; |
72 |
2351 |
closefd(&sock); |
73 |
2351 |
if (sz < 0) |
74 |
0 |
VRT_fail(ctx, "Barrier read failed: %s (errno=%d)", |
75 |
0 |
strerror(i), i); |
76 |
2351 |
if (sz > 0) |
77 |
0 |
VRT_fail(ctx, "Barrier unexpected data (%zdB)", sz); |
78 |
2351 |
} |
79 |
|
|
80 |
|
/*--------------------------------------------------------------------*/ |
81 |
|
|
82 |
|
VCL_BACKEND v_matchproto_(td_vtc_no_backend) |
83 |
80 |
vmod_no_backend(VRT_CTX) |
84 |
|
{ |
85 |
|
|
86 |
80 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
87 |
80 |
return (NULL); |
88 |
|
} |
89 |
|
|
90 |
|
VCL_STEVEDORE v_matchproto_(td_vtc_no_stevedore) |
91 |
40 |
vmod_no_stevedore(VRT_CTX) |
92 |
|
{ |
93 |
|
|
94 |
40 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
95 |
40 |
return (NULL); |
96 |
|
} |
97 |
|
|
98 |
|
VCL_IP v_matchproto_(td_vtc_no_ip) |
99 |
40 |
vmod_no_ip(VRT_CTX) |
100 |
|
{ |
101 |
|
|
102 |
40 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
103 |
40 |
return (NULL); |
104 |
|
} |
105 |
|
|
106 |
|
/*--------------------------------------------------------------------*/ |
107 |
|
|
108 |
|
VCL_VOID v_noreturn_ v_matchproto_(td_vtc_panic) |
109 |
0 |
vmod_panic(VRT_CTX, VCL_STRANDS str) |
110 |
|
{ |
111 |
|
const char *b; |
112 |
|
|
113 |
0 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
114 |
|
|
115 |
0 |
b = VRT_StrandsWS(ctx->ws, "PANIC:", str); |
116 |
0 |
VAS_Fail("VCL", "", 0, b, VAS_VCL); |
117 |
|
} |
118 |
|
|
119 |
|
/*--------------------------------------------------------------------*/ |
120 |
|
|
121 |
|
VCL_VOID v_matchproto_(td_vtc_sleep) |
122 |
1000 |
vmod_sleep(VRT_CTX, VCL_DURATION t) |
123 |
|
{ |
124 |
|
|
125 |
1000 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
126 |
1000 |
VTIM_sleep(t); |
127 |
1000 |
} |
128 |
|
|
129 |
|
/*--------------------------------------------------------------------*/ |
130 |
|
|
131 |
|
// XXX this really should be PRIV_TASK state |
132 |
|
static uintptr_t vtc_ws_snapshot; |
133 |
|
|
134 |
|
static struct ws * |
135 |
21560 |
vtc_ws_find(VRT_CTX, VCL_ENUM which) |
136 |
|
{ |
137 |
|
|
138 |
21560 |
if (which == VENUM(client)) |
139 |
10320 |
return (ctx->ws); |
140 |
11240 |
if (which == VENUM(backend)) |
141 |
10080 |
return (ctx->bo->ws); |
142 |
1160 |
if (which == VENUM(session)) |
143 |
1080 |
return (ctx->req->sp->ws); |
144 |
80 |
if (which == VENUM(thread) && ctx->req != NULL) |
145 |
80 |
return (ctx->req->wrk->aws); |
146 |
0 |
if (which == VENUM(thread) && ctx->bo != NULL) |
147 |
0 |
return (ctx->bo->wrk->aws); |
148 |
0 |
WRONG("vtc_ws_find Illegal enum"); |
149 |
21560 |
} |
150 |
|
|
151 |
|
VCL_VOID v_matchproto_(td_vtc_workspace_alloc) |
152 |
19640 |
vmod_workspace_alloc(VRT_CTX, VCL_ENUM which, VCL_INT size) |
153 |
|
{ |
154 |
|
struct ws *ws; |
155 |
|
void *p; |
156 |
|
|
157 |
19640 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
158 |
|
|
159 |
19640 |
ws = vtc_ws_find(ctx, which); |
160 |
19640 |
if (ws == NULL) |
161 |
0 |
return; |
162 |
19640 |
WS_Assert(ws); |
163 |
|
|
164 |
19640 |
if (size < 0) { |
165 |
19000 |
size += WS_ReserveAll(ws); |
166 |
19000 |
WS_Release(ws, 0); |
167 |
19000 |
} |
168 |
19640 |
if (size <= 0) { |
169 |
80 |
VRT_fail(ctx, "Attempted negative WS allocation"); |
170 |
80 |
return; |
171 |
|
} |
172 |
19560 |
p = WS_Alloc(ws, size); |
173 |
19560 |
if (p == NULL) |
174 |
40 |
VRT_fail(ctx, "vtc.workspace_alloc"); |
175 |
|
else |
176 |
19520 |
memset(p, '\0', size); |
177 |
19640 |
} |
178 |
|
|
179 |
|
VCL_BYTES v_matchproto_(td_vtc_workspace_reserve) |
180 |
480 |
vmod_workspace_reserve(VRT_CTX, VCL_ENUM which, VCL_INT size) |
181 |
|
{ |
182 |
|
struct ws *ws; |
183 |
|
unsigned r; |
184 |
|
|
185 |
480 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
186 |
|
|
187 |
480 |
ws = vtc_ws_find(ctx, which); |
188 |
480 |
if (ws == NULL) |
189 |
0 |
return (0); |
190 |
480 |
WS_Assert(ws); |
191 |
|
|
192 |
480 |
if (size < 0) { |
193 |
280 |
size += WS_ReserveAll(ws); |
194 |
280 |
WS_Release(ws, 0); |
195 |
280 |
} |
196 |
480 |
if (size <= 0) { |
197 |
0 |
VRT_fail(ctx, "Attempted negative WS reservation"); |
198 |
0 |
return (0); |
199 |
|
} |
200 |
480 |
r = WS_ReserveSize(ws, size); |
201 |
480 |
if (r == 0) |
202 |
40 |
return (0); |
203 |
440 |
memset(WS_Reservation(ws), 0, r); |
204 |
440 |
WS_Release(ws, 0); |
205 |
440 |
return (r); |
206 |
480 |
} |
207 |
|
|
208 |
|
VCL_INT v_matchproto_(td_vtc_workspace_free) |
209 |
640 |
vmod_workspace_free(VRT_CTX, VCL_ENUM which) |
210 |
|
{ |
211 |
|
struct ws *ws; |
212 |
|
unsigned u; |
213 |
|
|
214 |
640 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
215 |
|
|
216 |
640 |
ws = vtc_ws_find(ctx, which); |
217 |
640 |
if (ws == NULL) |
218 |
0 |
return (-1); |
219 |
640 |
WS_Assert(ws); |
220 |
|
|
221 |
640 |
u = WS_ReserveAll(ws); |
222 |
640 |
WS_Release(ws, 0); |
223 |
640 |
return (u); |
224 |
640 |
} |
225 |
|
|
226 |
|
#define VTC_WS_OP(type, def, name, op) \ |
227 |
|
VCL_##type v_matchproto_(td_vtc_workspace_##name) \ |
228 |
|
vmod_workspace_##name(VRT_CTX, VCL_ENUM which) \ |
229 |
|
{ \ |
230 |
|
struct ws *ws; \ |
231 |
|
\ |
232 |
|
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \ |
233 |
|
\ |
234 |
|
ws = vtc_ws_find(ctx, which); \ |
235 |
|
if (ws == NULL) \ |
236 |
|
return def ; \ |
237 |
|
WS_Assert(ws); \ |
238 |
|
\ |
239 |
|
op; \ |
240 |
|
} |
241 |
40 |
VTC_WS_OP(VOID, , snapshot, (vtc_ws_snapshot = WS_Snapshot(ws))) |
242 |
40 |
VTC_WS_OP(VOID, , reset, WS_Reset(ws, vtc_ws_snapshot)) |
243 |
40 |
VTC_WS_OP(VOID, , overflow, WS_MarkOverflow(ws)) |
244 |
200 |
VTC_WS_OP(BOOL, (0), overflowed, return (WS_Overflowed(ws))) |
245 |
|
#undef VTC_WS_OP |
246 |
|
|
247 |
|
VCL_BLOB v_matchproto_(td_vtc_workspace_dump) |
248 |
479 |
vmod_workspace_dump(VRT_CTX, VCL_ENUM which, VCL_ENUM where, |
249 |
|
VCL_BYTES off, VCL_BYTES len) |
250 |
|
{ |
251 |
|
struct ws *ws; |
252 |
|
unsigned l; |
253 |
479 |
const unsigned maxlen = 1024; |
254 |
479 |
unsigned char buf[maxlen]; |
255 |
|
const char *p, *err; |
256 |
|
|
257 |
479 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
258 |
479 |
AN(where); |
259 |
|
|
260 |
479 |
ws = vtc_ws_find(ctx, which); |
261 |
479 |
if (ws == NULL) |
262 |
0 |
return (NULL); |
263 |
479 |
WS_Assert(ws); |
264 |
|
|
265 |
479 |
if (len > maxlen) { |
266 |
0 |
VRT_fail(ctx, "workspace_dump: max length is %jd", |
267 |
|
(intmax_t)maxlen); |
268 |
0 |
return (NULL); |
269 |
|
} |
270 |
|
|
271 |
479 |
l = WS_Dump(ws, *where, off, buf, len); |
272 |
479 |
assert(l <= maxlen); |
273 |
|
|
274 |
479 |
if (l == 0) { |
275 |
0 |
switch (errno) { |
276 |
0 |
case EINVAL: WRONG(where); break; |
277 |
0 |
case EAGAIN: err = "NULL"; break; |
278 |
0 |
case EFAULT: err = "off limit"; break; |
279 |
0 |
default: err = "unknown error"; break; |
280 |
|
} |
281 |
0 |
VRT_fail(ctx, "workspace_dump: %s", err); |
282 |
0 |
return (NULL); |
283 |
|
} |
284 |
|
|
285 |
479 |
p = WS_Copy(ctx->ws, buf, (int)l); |
286 |
479 |
if (p == NULL) { |
287 |
0 |
VRT_fail(ctx, "workspace_dump: copy failed"); |
288 |
0 |
return (NULL); |
289 |
|
} |
290 |
479 |
return (VRT_blob(ctx, "workspace_dump", p, l, 0xd000d000)); |
291 |
479 |
} |
292 |
|
|
293 |
|
/*--------------------------------------------------------------------*/ |
294 |
|
|
295 |
|
VCL_INT v_matchproto_(td_vtc_typesize) |
296 |
1000 |
vmod_typesize(VRT_CTX, VCL_STRING s) |
297 |
|
{ |
298 |
1000 |
size_t i = 0, l, a, p = 0; |
299 |
|
|
300 |
1000 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
301 |
1000 |
AN(s); |
302 |
1000 |
AN(*s); |
303 |
|
|
304 |
3920 |
for (; *s; s++) { |
305 |
2960 |
switch (*s) { |
306 |
|
#define VTC_TYPESIZE(c, t) case c: l = sizeof(t); break; |
307 |
440 |
VTC_TYPESIZE('c', char) |
308 |
120 |
VTC_TYPESIZE('d', double) |
309 |
40 |
VTC_TYPESIZE('f', float) |
310 |
120 |
VTC_TYPESIZE('i', int) |
311 |
40 |
VTC_TYPESIZE('j', intmax_t) |
312 |
40 |
VTC_TYPESIZE('l', long) |
313 |
40 |
VTC_TYPESIZE('o', off_t) |
314 |
640 |
VTC_TYPESIZE('p', void *) |
315 |
120 |
VTC_TYPESIZE('s', short) |
316 |
600 |
VTC_TYPESIZE('u', unsigned) |
317 |
720 |
VTC_TYPESIZE('z', size_t) |
318 |
|
#undef VTC_TYPESIZE |
319 |
40 |
default: return (-1); |
320 |
|
} |
321 |
2920 |
if (l > p) |
322 |
1680 |
p = l; |
323 |
2920 |
a = i % l; |
324 |
2920 |
if (a != 0) |
325 |
760 |
i += (l - a); /* align */ |
326 |
2920 |
i += l; |
327 |
2920 |
} |
328 |
960 |
AN(p); |
329 |
960 |
a = i % p; |
330 |
960 |
if (a != 0) |
331 |
240 |
i += (p - a); /* pad */ |
332 |
960 |
return ((VCL_INT)i); |
333 |
1000 |
} |
334 |
|
|
335 |
|
/*--------------------------------------------------------------------*/ |
336 |
|
|
337 |
|
#define BLOB_VMOD_PROXY_HEADER_TYPE 0xc8f34f78 |
338 |
|
|
339 |
|
VCL_BLOB v_matchproto_(td_vtc_proxy_header) |
340 |
80 |
vmod_proxy_header(VRT_CTX, VCL_ENUM venum, VCL_IP client, VCL_IP server, |
341 |
|
VCL_STRING authority) |
342 |
|
{ |
343 |
|
struct vsb *vsb; |
344 |
|
const void *h; |
345 |
|
int version; |
346 |
|
size_t l; |
347 |
|
|
348 |
80 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
349 |
|
|
350 |
80 |
if (venum == VENUM(v1)) |
351 |
40 |
version = 1; |
352 |
40 |
else if (venum == VENUM(v2)) |
353 |
40 |
version = 2; |
354 |
|
else |
355 |
0 |
WRONG(venum); |
356 |
|
|
357 |
80 |
vsb = VSB_new_auto(); |
358 |
80 |
AN(vsb); |
359 |
80 |
VRT_Format_Proxy(vsb, version, client, server, authority); |
360 |
80 |
l = VSB_len(vsb); |
361 |
80 |
h = WS_Copy(ctx->ws, VSB_data(vsb), l); |
362 |
80 |
VSB_destroy(&vsb); |
363 |
|
|
364 |
80 |
if (h == NULL) { |
365 |
0 |
VRT_fail(ctx, "proxy_header: out of workspace"); |
366 |
0 |
return (NULL); |
367 |
|
} |
368 |
|
|
369 |
80 |
return (VRT_blob(ctx, "proxy_header", h, l, |
370 |
|
BLOB_VMOD_PROXY_HEADER_TYPE)); |
371 |
80 |
} |
372 |
|
|
373 |
|
// ref vsl.c |
374 |
|
struct vsl_tag2enum { |
375 |
|
const char *string; |
376 |
|
enum VSL_tag_e tag; |
377 |
|
}; |
378 |
|
|
379 |
|
static struct vsl_tag2enum vsl_tag2enum[SLT__MAX] = { |
380 |
|
#define SLTM(name,flags,sdesc,ldesc) [SLT_ ## name] = { \ |
381 |
|
.string = #name, \ |
382 |
|
.tag = SLT_ ## name \ |
383 |
|
}, |
384 |
|
#include "tbl/vsl_tags.h" |
385 |
|
}; |
386 |
|
|
387 |
|
static int |
388 |
2368560 |
vsl_tagcmp(const void *aa, const void *bb) |
389 |
|
{ |
390 |
2368560 |
const struct vsl_tag2enum *a = aa, *b = bb; |
391 |
|
|
392 |
|
// ref vsl2rst.c ptag_cmp |
393 |
2368560 |
if (a->string == NULL && b->string != NULL) |
394 |
5360 |
return (1); |
395 |
2363200 |
else if (a->string != NULL && b->string == NULL) |
396 |
258240 |
return (-1); |
397 |
2104960 |
else if (a->string == NULL && b->string == NULL) |
398 |
452920 |
return (0); |
399 |
1652040 |
return (strcmp(a->string, b->string)); |
400 |
2368560 |
} |
401 |
|
|
402 |
|
/*lint -esym(528, init_vsl_tag2enum) */ |
403 |
|
static void __attribute__((constructor)) |
404 |
2680 |
init_vsl_tag2enum(void) |
405 |
|
{ |
406 |
2680 |
qsort(vsl_tag2enum, SLT__MAX, sizeof *vsl_tag2enum, vsl_tagcmp); |
407 |
2680 |
} |
408 |
|
|
409 |
|
|
410 |
|
VCL_VOID |
411 |
2440 |
vmod_vsl(VRT_CTX, VCL_INT id, VCL_STRING tag_s, VCL_ENUM side, VCL_STRANDS s) |
412 |
|
{ |
413 |
|
struct vsl_tag2enum *te, key; |
414 |
|
vxid_t vxid; |
415 |
|
|
416 |
2440 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
417 |
|
|
418 |
2440 |
key.string = tag_s; |
419 |
2440 |
te = bsearch(&key, vsl_tag2enum, SLT__MAX, |
420 |
|
sizeof *vsl_tag2enum, vsl_tagcmp); |
421 |
|
|
422 |
2440 |
if (te == NULL) { |
423 |
0 |
VRT_fail(ctx, "No such tag: %s", tag_s); |
424 |
0 |
return; |
425 |
|
} |
426 |
|
|
427 |
2440 |
if (id < 0 || id > VRT_INTEGER_MAX) { |
428 |
0 |
VRT_fail(ctx, "id out of bounds"); |
429 |
0 |
return; |
430 |
|
} |
431 |
|
|
432 |
2440 |
vxid.vxid = id & VSL_IDENTMASK; |
433 |
2440 |
if (side == VENUM(c)) |
434 |
2360 |
vxid.vxid |= VSL_CLIENTMARKER; |
435 |
80 |
else if (side == VENUM(b)) |
436 |
80 |
vxid.vxid |= VSL_BACKENDMARKER; |
437 |
|
else |
438 |
0 |
WRONG("side"); |
439 |
|
|
440 |
2440 |
VSLs(te->tag, vxid, s); |
441 |
2440 |
} |
442 |
|
|
443 |
|
static void |
444 |
2360 |
vsl_line(VRT_CTX, char *str) |
445 |
|
{ |
446 |
|
VCL_INT id; |
447 |
|
VCL_ENUM side; |
448 |
|
VCL_STRANDS s; |
449 |
2360 |
const char *tag, *delim = " \t\r\n"; |
450 |
|
char *e, *save; |
451 |
|
|
452 |
2360 |
if (*str == '*') { |
453 |
|
// varnishtest |
454 |
2200 |
str = strstr(str, "vsl|"); |
455 |
2200 |
if (str == NULL) |
456 |
0 |
return; |
457 |
2200 |
str += 4; |
458 |
2200 |
} |
459 |
2360 |
if ((str = strtok_r(str, delim, &save)) == NULL) |
460 |
160 |
return; |
461 |
2200 |
id = strtoll(str, &e, 10); |
462 |
2200 |
if (e == str) |
463 |
0 |
return; |
464 |
|
|
465 |
2200 |
if ((str = strtok_r(NULL, delim, &save)) == NULL) |
466 |
0 |
return; |
467 |
2200 |
tag = str; |
468 |
|
|
469 |
2200 |
if ((str = strtok_r(NULL, delim, &save)) == NULL) |
470 |
0 |
return; |
471 |
2200 |
if (*str == 'c') |
472 |
2120 |
side = VENUM(c); |
473 |
80 |
else if (*str == 'b') |
474 |
80 |
side = VENUM(b); |
475 |
|
else |
476 |
0 |
return; |
477 |
|
|
478 |
2200 |
str = strtok_r(NULL, "\r\n", &save); |
479 |
2200 |
s = TOSTRAND(str); |
480 |
2200 |
if (str == NULL) |
481 |
320 |
s = vrt_null_strands; |
482 |
|
|
483 |
2200 |
vmod_vsl(ctx, id, tag, side, s); |
484 |
2360 |
} |
485 |
|
|
486 |
|
VCL_VOID |
487 |
80 |
vmod_vsl_replay(VRT_CTX, VCL_STRANDS s) |
488 |
|
{ |
489 |
|
struct vsb cp[1]; |
490 |
|
const char *p, *pp; |
491 |
|
size_t l; |
492 |
80 |
int i, err = 0; |
493 |
|
|
494 |
80 |
if (s == NULL || s->n == 0) |
495 |
0 |
return; |
496 |
|
|
497 |
80 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
498 |
80 |
CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC); |
499 |
80 |
WS_VSB_new(cp, ctx->ws); |
500 |
|
|
501 |
160 |
for (i = 0; i < s->n; i++) { |
502 |
80 |
p = s->p[i]; |
503 |
80 |
if (p == NULL || *p == '\0') |
504 |
0 |
continue; |
505 |
80 |
pp = strpbrk(p, "\r\n"); |
506 |
2360 |
while (pp != NULL) { |
507 |
2280 |
l = pp - p; |
508 |
2280 |
if (VSB_bcat(cp, p, l) || VSB_finish(cp)) { |
509 |
0 |
err = 1; |
510 |
0 |
break; |
511 |
|
} |
512 |
2280 |
vsl_line(ctx, VSB_data(cp)); |
513 |
2280 |
VSB_clear(cp); |
514 |
2280 |
p = pp + 1; |
515 |
2280 |
pp = strpbrk(p, "\r\n"); |
516 |
|
} |
517 |
80 |
if (err || VSB_cat(cp, p)) { |
518 |
0 |
err = 1; |
519 |
0 |
break; |
520 |
|
} |
521 |
80 |
} |
522 |
80 |
if (err || VSB_finish(cp)) { |
523 |
0 |
AZ(WS_VSB_finish(cp, ctx->ws, NULL)); |
524 |
0 |
VRT_fail(ctx, "out of workspace"); |
525 |
0 |
return; |
526 |
|
} |
527 |
80 |
vsl_line(ctx, VSB_data(cp)); |
528 |
80 |
VSB_clear(cp); |
529 |
80 |
AN(WS_VSB_finish(cp, ctx->ws, NULL)); |
530 |
80 |
} |