| | 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 |
2160 |
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 |
2160 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
55 |
2160 |
AN(addr); |
56 |
2160 |
AN(*addr); |
57 |
2160 |
assert(tmo >= 0.0); |
58 |
|
|
59 |
2160 |
if (ctx->vsl != NULL) |
60 |
2160 |
VSLb(ctx->vsl, SLT_Debug, "barrier_sync(\"%s\")", addr); |
61 |
|
else |
62 |
0 |
VSL(SLT_Debug, NO_VXID, "barrier_sync(\"%s\")", addr); |
63 |
|
|
64 |
2160 |
sock = VTCP_open(addr, NULL, 0., &err); |
65 |
2160 |
if (sock < 0) { |
66 |
0 |
VRT_fail(ctx, "Barrier connection failed: %s", err); |
67 |
0 |
return; |
68 |
|
} |
69 |
|
|
70 |
2160 |
sz = VTCP_read(sock, buf, sizeof buf, tmo); |
71 |
2160 |
i = errno; |
72 |
2160 |
closefd(&sock); |
73 |
2160 |
if (sz < 0) |
74 |
0 |
VRT_fail(ctx, "Barrier read failed: %s (errno=%d)", |
75 |
0 |
strerror(i), i); |
76 |
2160 |
if (sz > 0) |
77 |
0 |
VRT_fail(ctx, "Barrier unexpected data (%zdB)", sz); |
78 |
2160 |
} |
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 |
680 |
vmod_sleep(VRT_CTX, VCL_DURATION t) |
123 |
|
{ |
124 |
|
|
125 |
680 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
126 |
680 |
VTIM_sleep(t); |
127 |
680 |
} |
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 |
21599 |
vtc_ws_find(VRT_CTX, VCL_ENUM which) |
136 |
|
{ |
137 |
|
|
138 |
21599 |
if (which == VENUM(client)) |
139 |
10320 |
return (ctx->ws); |
140 |
11279 |
if (which == VENUM(backend)) |
141 |
10120 |
return (ctx->bo->ws); |
142 |
1159 |
if (which == VENUM(session)) |
143 |
1079 |
return (ctx->req->sp->ws); |
144 |
80 |
if (which == VENUM(thread)) |
145 |
80 |
return (ctx->req->wrk->aws); |
146 |
0 |
WRONG("vtc_ws_find Illegal enum"); |
147 |
21599 |
} |
148 |
|
|
149 |
|
VCL_VOID v_matchproto_(td_vtc_workspace_alloc) |
150 |
19680 |
vmod_workspace_alloc(VRT_CTX, VCL_ENUM which, VCL_INT size) |
151 |
|
{ |
152 |
|
struct ws *ws; |
153 |
|
void *p; |
154 |
|
|
155 |
19680 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
156 |
|
|
157 |
19680 |
ws = vtc_ws_find(ctx, which); |
158 |
19680 |
if (ws == NULL) |
159 |
0 |
return; |
160 |
19680 |
WS_Assert(ws); |
161 |
|
|
162 |
19680 |
if (size < 0) { |
163 |
19000 |
size += WS_ReserveAll(ws); |
164 |
19000 |
WS_Release(ws, 0); |
165 |
19000 |
} |
166 |
19680 |
if (size <= 0) { |
167 |
120 |
VRT_fail(ctx, "Attempted negative WS allocation"); |
168 |
120 |
return; |
169 |
|
} |
170 |
19560 |
p = WS_Alloc(ws, size); |
171 |
19560 |
if (p == NULL) |
172 |
40 |
VRT_fail(ctx, "vtc.workspace_alloc"); |
173 |
|
else |
174 |
19520 |
memset(p, '\0', size); |
175 |
19680 |
} |
176 |
|
|
177 |
|
VCL_BYTES v_matchproto_(td_vtc_workspace_reserve) |
178 |
480 |
vmod_workspace_reserve(VRT_CTX, VCL_ENUM which, VCL_INT size) |
179 |
|
{ |
180 |
|
struct ws *ws; |
181 |
|
unsigned r; |
182 |
|
|
183 |
480 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
184 |
|
|
185 |
480 |
ws = vtc_ws_find(ctx, which); |
186 |
480 |
if (ws == NULL) |
187 |
0 |
return (0); |
188 |
480 |
WS_Assert(ws); |
189 |
|
|
190 |
480 |
if (size < 0) { |
191 |
280 |
size += WS_ReserveAll(ws); |
192 |
280 |
WS_Release(ws, 0); |
193 |
280 |
} |
194 |
480 |
if (size <= 0) { |
195 |
0 |
VRT_fail(ctx, "Attempted negative WS reservation"); |
196 |
0 |
return (0); |
197 |
|
} |
198 |
480 |
r = WS_ReserveSize(ws, size); |
199 |
480 |
if (r == 0) |
200 |
40 |
return (0); |
201 |
440 |
memset(WS_Reservation(ws), 0, r); |
202 |
440 |
WS_Release(ws, 0); |
203 |
440 |
return (r); |
204 |
480 |
} |
205 |
|
|
206 |
|
VCL_INT v_matchproto_(td_vtc_workspace_free) |
207 |
640 |
vmod_workspace_free(VRT_CTX, VCL_ENUM which) |
208 |
|
{ |
209 |
|
struct ws *ws; |
210 |
|
unsigned u; |
211 |
|
|
212 |
640 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
213 |
|
|
214 |
640 |
ws = vtc_ws_find(ctx, which); |
215 |
640 |
if (ws == NULL) |
216 |
0 |
return (-1); |
217 |
640 |
WS_Assert(ws); |
218 |
|
|
219 |
640 |
u = WS_ReserveAll(ws); |
220 |
640 |
WS_Release(ws, 0); |
221 |
640 |
return (u); |
222 |
640 |
} |
223 |
|
|
224 |
|
#define VTC_WS_OP(type, def, name, op) \ |
225 |
|
VCL_##type v_matchproto_(td_vtc_workspace_##name) \ |
226 |
|
vmod_workspace_##name(VRT_CTX, VCL_ENUM which) \ |
227 |
|
{ \ |
228 |
|
struct ws *ws; \ |
229 |
|
\ |
230 |
|
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \ |
231 |
|
\ |
232 |
|
ws = vtc_ws_find(ctx, which); \ |
233 |
|
if (ws == NULL) \ |
234 |
|
return def ; \ |
235 |
|
WS_Assert(ws); \ |
236 |
|
\ |
237 |
|
op; \ |
238 |
|
} |
239 |
40 |
VTC_WS_OP(VOID, , snapshot, (vtc_ws_snapshot = WS_Snapshot(ws))) |
240 |
40 |
VTC_WS_OP(VOID, , reset, WS_Reset(ws, vtc_ws_snapshot)) |
241 |
40 |
VTC_WS_OP(VOID, , overflow, WS_MarkOverflow(ws)) |
242 |
200 |
VTC_WS_OP(BOOL, (0), overflowed, return (WS_Overflowed(ws))) |
243 |
|
#undef VTC_WS_OP |
244 |
|
|
245 |
|
VCL_BLOB v_matchproto_(td_vtc_workspace_dump) |
246 |
477 |
vmod_workspace_dump(VRT_CTX, VCL_ENUM which, VCL_ENUM where, |
247 |
|
VCL_BYTES off, VCL_BYTES len) |
248 |
|
{ |
249 |
|
struct ws *ws; |
250 |
477 |
VCL_BYTES l, maxlen = 1024; |
251 |
477 |
unsigned char buf[maxlen]; |
252 |
|
const char *p, *err; |
253 |
|
|
254 |
477 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
255 |
477 |
AN(where); |
256 |
|
|
257 |
477 |
ws = vtc_ws_find(ctx, which); |
258 |
477 |
if (ws == NULL) |
259 |
0 |
return (NULL); |
260 |
477 |
WS_Assert(ws); |
261 |
|
|
262 |
477 |
if (len > maxlen) { |
263 |
0 |
VRT_fail(ctx, "workspace_dump: max length is %jd", |
264 |
0 |
(intmax_t)maxlen); |
265 |
0 |
return (NULL); |
266 |
|
} |
267 |
|
|
268 |
477 |
l = WS_Dump(ws, *where, off, buf, len); |
269 |
|
|
270 |
477 |
if (l == 0) { |
271 |
0 |
switch (errno) { |
272 |
0 |
case EINVAL: WRONG(where); break; |
273 |
0 |
case EAGAIN: err = "NULL"; break; |
274 |
0 |
case EFAULT: err = "off limit"; break; |
275 |
0 |
default: err = "unknown error"; break; |
276 |
|
} |
277 |
0 |
VRT_fail(ctx, "workspace_dump: %s", err); |
278 |
0 |
return (NULL); |
279 |
|
} |
280 |
|
|
281 |
477 |
assert(l < maxlen); |
282 |
477 |
p = WS_Copy(ctx->ws, buf, l); |
283 |
477 |
if (p == NULL) { |
284 |
0 |
VRT_fail(ctx, "workspace_dump: copy failed"); |
285 |
0 |
return (NULL); |
286 |
|
} |
287 |
477 |
return (VRT_blob(ctx, "workspace_dump", p, l, 0xd000d000)); |
288 |
477 |
} |
289 |
|
|
290 |
|
/*--------------------------------------------------------------------*/ |
291 |
|
|
292 |
|
VCL_INT v_matchproto_(td_vtc_typesize) |
293 |
1000 |
vmod_typesize(VRT_CTX, VCL_STRING s) |
294 |
|
{ |
295 |
1000 |
size_t i = 0, l, a, p = 0; |
296 |
|
|
297 |
1000 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
298 |
1000 |
AN(s); |
299 |
1000 |
AN(*s); |
300 |
|
|
301 |
3920 |
for (; *s; s++) { |
302 |
2960 |
switch (*s) { |
303 |
|
#define VTC_TYPESIZE(c, t) case c: l = sizeof(t); break; |
304 |
440 |
VTC_TYPESIZE('c', char) |
305 |
120 |
VTC_TYPESIZE('d', double) |
306 |
40 |
VTC_TYPESIZE('f', float) |
307 |
120 |
VTC_TYPESIZE('i', int) |
308 |
40 |
VTC_TYPESIZE('j', intmax_t) |
309 |
40 |
VTC_TYPESIZE('l', long) |
310 |
40 |
VTC_TYPESIZE('o', off_t) |
311 |
640 |
VTC_TYPESIZE('p', void *) |
312 |
120 |
VTC_TYPESIZE('s', short) |
313 |
600 |
VTC_TYPESIZE('u', unsigned) |
314 |
720 |
VTC_TYPESIZE('z', size_t) |
315 |
|
#undef VTC_TYPESIZE |
316 |
40 |
default: return (-1); |
317 |
|
} |
318 |
2920 |
if (l > p) |
319 |
1680 |
p = l; |
320 |
2920 |
a = i % l; |
321 |
2920 |
if (a != 0) |
322 |
760 |
i += (l - a); /* align */ |
323 |
2920 |
i += l; |
324 |
2920 |
} |
325 |
960 |
AN(p); |
326 |
960 |
a = i % p; |
327 |
960 |
if (a != 0) |
328 |
240 |
i += (p - a); /* pad */ |
329 |
960 |
return ((VCL_INT)i); |
330 |
1000 |
} |
331 |
|
|
332 |
|
/*--------------------------------------------------------------------*/ |
333 |
|
|
334 |
|
#define BLOB_VMOD_PROXY_HEADER_TYPE 0xc8f34f78 |
335 |
|
|
336 |
|
VCL_BLOB v_matchproto_(td_vtc_proxy_header) |
337 |
80 |
vmod_proxy_header(VRT_CTX, VCL_ENUM venum, VCL_IP client, VCL_IP server, |
338 |
|
VCL_STRING authority) |
339 |
|
{ |
340 |
|
struct vsb *vsb; |
341 |
|
const void *h; |
342 |
|
int version; |
343 |
|
size_t l; |
344 |
|
|
345 |
80 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
346 |
|
|
347 |
80 |
if (venum == VENUM(v1)) |
348 |
40 |
version = 1; |
349 |
40 |
else if (venum == VENUM(v2)) |
350 |
40 |
version = 2; |
351 |
|
else |
352 |
0 |
WRONG(venum); |
353 |
|
|
354 |
80 |
vsb = VSB_new_auto(); |
355 |
80 |
AN(vsb); |
356 |
80 |
VRT_Format_Proxy(vsb, version, client, server, authority); |
357 |
80 |
l = VSB_len(vsb); |
358 |
80 |
h = WS_Copy(ctx->ws, VSB_data(vsb), l); |
359 |
80 |
VSB_destroy(&vsb); |
360 |
|
|
361 |
80 |
if (h == NULL) { |
362 |
0 |
VRT_fail(ctx, "proxy_header: out of workspace"); |
363 |
0 |
return (NULL); |
364 |
|
} |
365 |
|
|
366 |
80 |
return (VRT_blob(ctx, "proxy_header", h, l, |
367 |
|
BLOB_VMOD_PROXY_HEADER_TYPE)); |
368 |
80 |
} |
369 |
|
|
370 |
|
// ref vsl.c |
371 |
|
struct vsl_tag2enum { |
372 |
|
const char *string; |
373 |
|
enum VSL_tag_e tag; |
374 |
|
}; |
375 |
|
|
376 |
|
static struct vsl_tag2enum vsl_tag2enum[SLT__MAX] = { |
377 |
|
#define SLTM(name,flags,sdesc,ldesc) [SLT_ ## name] = { \ |
378 |
|
.string = #name, \ |
379 |
|
.tag = SLT_ ## name \ |
380 |
|
}, |
381 |
|
#include "tbl/vsl_tags.h" |
382 |
|
}; |
383 |
|
|
384 |
|
static int |
385 |
2333480 |
vsl_tagcmp(const void *aa, const void *bb) |
386 |
|
{ |
387 |
2333480 |
const struct vsl_tag2enum *a = aa, *b = bb; |
388 |
|
|
389 |
|
// ref vsl2rst.c ptag_cmp |
390 |
2333480 |
if (a->string == NULL && b->string != NULL) |
391 |
5280 |
return (1); |
392 |
2328200 |
else if (a->string != NULL && b->string == NULL) |
393 |
254440 |
return (-1); |
394 |
2073760 |
else if (a->string == NULL && b->string == NULL) |
395 |
446160 |
return (0); |
396 |
1627600 |
return (strcmp(a->string, b->string)); |
397 |
2333480 |
} |
398 |
|
|
399 |
|
/*lint -esym(528, init_vsl_tag2enum) */ |
400 |
|
static void __attribute__((constructor)) |
401 |
2640 |
init_vsl_tag2enum(void) |
402 |
|
{ |
403 |
2640 |
qsort(vsl_tag2enum, SLT__MAX, sizeof *vsl_tag2enum, vsl_tagcmp); |
404 |
2640 |
} |
405 |
|
|
406 |
|
|
407 |
|
VCL_VOID |
408 |
2440 |
vmod_vsl(VRT_CTX, VCL_INT id, VCL_STRING tag_s, VCL_ENUM side, VCL_STRANDS s) |
409 |
|
{ |
410 |
|
struct vsl_tag2enum *te, key; |
411 |
|
vxid_t vxid; |
412 |
|
|
413 |
2440 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
414 |
|
|
415 |
2440 |
key.string = tag_s; |
416 |
2440 |
te = bsearch(&key, vsl_tag2enum, SLT__MAX, |
417 |
|
sizeof *vsl_tag2enum, vsl_tagcmp); |
418 |
|
|
419 |
2440 |
if (te == NULL) { |
420 |
0 |
VRT_fail(ctx, "No such tag: %s", tag_s); |
421 |
0 |
return; |
422 |
|
} |
423 |
|
|
424 |
2440 |
if (id < 0 || id > VRT_INTEGER_MAX) { |
425 |
0 |
VRT_fail(ctx, "id out of bounds"); |
426 |
0 |
return; |
427 |
|
} |
428 |
|
|
429 |
2440 |
vxid.vxid = id & VSL_IDENTMASK; |
430 |
2440 |
if (side == VENUM(c)) |
431 |
2360 |
vxid.vxid |= VSL_CLIENTMARKER; |
432 |
80 |
else if (side == VENUM(b)) |
433 |
80 |
vxid.vxid |= VSL_BACKENDMARKER; |
434 |
|
else |
435 |
0 |
WRONG("side"); |
436 |
|
|
437 |
2440 |
VSLs(te->tag, vxid, s); |
438 |
2440 |
} |
439 |
|
|
440 |
|
static void |
441 |
2360 |
vsl_line(VRT_CTX, char *str) |
442 |
|
{ |
443 |
|
VCL_INT id; |
444 |
|
VCL_ENUM side; |
445 |
|
VCL_STRANDS s; |
446 |
2360 |
const char *tag, *delim = " \t\r\n"; |
447 |
|
char *e, *save; |
448 |
|
|
449 |
2360 |
if (*str == '*') { |
450 |
|
// varnishtest |
451 |
2200 |
str = strstr(str, "vsl|"); |
452 |
2200 |
if (str == NULL) |
453 |
0 |
return; |
454 |
2200 |
str += 4; |
455 |
2200 |
} |
456 |
2360 |
if ((str = strtok_r(str, delim, &save)) == NULL) |
457 |
160 |
return; |
458 |
2200 |
id = strtoll(str, &e, 10); |
459 |
2200 |
if (e == str) |
460 |
0 |
return; |
461 |
|
|
462 |
2200 |
if ((str = strtok_r(NULL, delim, &save)) == NULL) |
463 |
0 |
return; |
464 |
2200 |
tag = str; |
465 |
|
|
466 |
2200 |
if ((str = strtok_r(NULL, delim, &save)) == NULL) |
467 |
0 |
return; |
468 |
2200 |
if (*str == 'c') |
469 |
2120 |
side = VENUM(c); |
470 |
80 |
else if (*str == 'b') |
471 |
80 |
side = VENUM(b); |
472 |
|
else |
473 |
0 |
return; |
474 |
|
|
475 |
2200 |
str = strtok_r(NULL, "\r\n", &save); |
476 |
2200 |
s = TOSTRAND(str); |
477 |
2200 |
if (str == NULL) |
478 |
320 |
s = vrt_null_strands; |
479 |
|
|
480 |
2200 |
vmod_vsl(ctx, id, tag, side, s); |
481 |
2360 |
} |
482 |
|
|
483 |
|
VCL_VOID |
484 |
80 |
vmod_vsl_replay(VRT_CTX, VCL_STRANDS s) |
485 |
|
{ |
486 |
|
struct vsb cp[1]; |
487 |
|
const char *p, *pp; |
488 |
|
size_t l; |
489 |
80 |
int i, err = 0; |
490 |
|
|
491 |
80 |
if (s == NULL || s->n == 0) |
492 |
0 |
return; |
493 |
|
|
494 |
80 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
495 |
80 |
CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC); |
496 |
80 |
WS_VSB_new(cp, ctx->ws); |
497 |
|
|
498 |
160 |
for (i = 0; i < s->n; i++) { |
499 |
80 |
p = s->p[i]; |
500 |
80 |
if (p == NULL || *p == '\0') |
501 |
0 |
continue; |
502 |
80 |
pp = strpbrk(p, "\r\n"); |
503 |
2360 |
while (pp != NULL) { |
504 |
2280 |
l = pp - p; |
505 |
2280 |
if (VSB_bcat(cp, p, l) || VSB_finish(cp)) { |
506 |
0 |
err = 1; |
507 |
0 |
break; |
508 |
|
} |
509 |
2280 |
vsl_line(ctx, VSB_data(cp)); |
510 |
2280 |
VSB_clear(cp); |
511 |
2280 |
p = pp + 1; |
512 |
2280 |
pp = strpbrk(p, "\r\n"); |
513 |
|
} |
514 |
80 |
if (err || VSB_cat(cp, p)) { |
515 |
0 |
err = 1; |
516 |
0 |
break; |
517 |
|
} |
518 |
80 |
} |
519 |
80 |
if (err || VSB_finish(cp)) { |
520 |
0 |
AZ(WS_VSB_finish(cp, ctx->ws, NULL)); |
521 |
0 |
VRT_fail(ctx, "out of workspace"); |
522 |
0 |
return; |
523 |
|
} |
524 |
80 |
vsl_line(ctx, VSB_data(cp)); |
525 |
80 |
VSB_clear(cp); |
526 |
80 |
AN(WS_VSB_finish(cp, ctx->ws, NULL)); |
527 |
80 |
} |