1 /*-
2 * Copyright (c) 2006 Verdens Gang AS
3 * Copyright (c) 2006-2015 Varnish Software AS
4 * All rights reserved.
5 *
6 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7 *
8 * SPDX-License-Identifier: BSD-2-Clause
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * Runtime support for compiled VCL programs
32 */
33 #include "config.h"
34
35 #include <stdio.h>
36
37 #include "cache_varnishd.h"
38 #include "common/heritage.h"
39
40 #include "vcl.h"
41 #include "vtim.h"
42 #include "vtcp.h"
43
44 #include "vrt_obj.h"
45
46 static char vrt_hostname[255] = "";
47
48 /*--------------------------------------------------------------------
49 * VRT variables relating to first line of HTTP/1.1 req/resp
50 */
51
52 static void
vrt_do_string(VRT_CTX,struct http * hp,int fld,const char * err,const char * p,va_list ap)53 vrt_do_string(VRT_CTX, struct http *hp, int fld,
54 const char *err, const char *p, va_list ap)
55 {
56 const char *b;
57
58 CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
59
60 b = VRT_String(hp->ws, NULL, p, ap);
61 if (b == NULL) {
62 VRT_fail(ctx, "Workspace overflow (%s)", err);
63 WS_MarkOverflow(hp->ws);
64 return;
65 }
66 if (*b == '\0') {
67 VRT_fail(ctx, "Setting %s to empty string", err);
68 return;
69 }
70 http_SetH(hp, fld, b);
71 }
72
73 #define VRT_HDR_L(obj, hdr, fld) \
74 VCL_VOID \
75 VRT_l_##obj##_##hdr(VRT_CTX, const char *p, ...) \
76 { \
77 va_list ap; \
78 \
79 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
80 va_start(ap, p); \
81 vrt_do_string(ctx, ctx->http_##obj, fld, #obj "." #hdr, p, ap); \
82 va_end(ap); \
83 }
84
85 #define VRT_HDR_R(obj, hdr, fld) \
86 VCL_STRING \
87 VRT_r_##obj##_##hdr(VRT_CTX) \
88 { \
89 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
90 CHECK_OBJ_NOTNULL(ctx->http_##obj, HTTP_MAGIC); \
91 return (ctx->http_##obj->hd[fld].b); \
92 }
93
94 #define VRT_HDR_LR(obj, hdr, fld) \
95 VRT_HDR_L(obj, hdr, fld) \
96 VRT_HDR_R(obj, hdr, fld)
97
98 #define VRT_STATUS_L(obj) \
99 VCL_VOID \
100 VRT_l_##obj##_status(VRT_CTX, VCL_INT num) \
101 { \
102 \
103 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
104 CHECK_OBJ_NOTNULL(ctx->http_##obj, HTTP_MAGIC); \
105 if (num < 0) \
106 VRT_fail(ctx, "%s.status (%jd) is negative", \
107 #obj, (intmax_t)num); \
108 else if (num > 65535) \
109 VRT_fail(ctx, "%s.status (%jd) > 65535", \
110 #obj, (intmax_t)num); \
111 else if ((num % 1000) < 100) \
112 VRT_fail(ctx, "illegal %s.status (%jd) (..0##)", \
113 #obj, (intmax_t)num); \
114 else \
115 http_SetStatus(ctx->http_##obj, (uint16_t)num, NULL); \
116 }
117
118 #define VRT_STATUS_R(obj) \
119 VCL_INT \
120 VRT_r_##obj##_status(VRT_CTX) \
121 { \
122 \
123 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
124 CHECK_OBJ_NOTNULL(ctx->http_##obj, HTTP_MAGIC); \
125 return (ctx->http_##obj->status); \
126 }
127
VRT_HDR_LR(req,method,HTTP_HDR_METHOD)128 VRT_HDR_LR(req, method, HTTP_HDR_METHOD)
129 VRT_HDR_LR(req, url, HTTP_HDR_URL)
130 VRT_HDR_LR(req, proto, HTTP_HDR_PROTO)
131
132 VRT_HDR_R(req_top, method, HTTP_HDR_METHOD)
133 VRT_HDR_R(req_top, url, HTTP_HDR_URL)
134 VRT_HDR_R(req_top, proto, HTTP_HDR_PROTO)
135
136 VRT_HDR_LR(resp, proto, HTTP_HDR_PROTO)
137 VRT_HDR_LR(resp, reason, HTTP_HDR_REASON)
138 VRT_STATUS_L(resp)
139 VRT_STATUS_R(resp)
140
141 VRT_HDR_LR(bereq, method, HTTP_HDR_METHOD)
142 VRT_HDR_LR(bereq, url, HTTP_HDR_URL)
143 VRT_HDR_LR(bereq, proto, HTTP_HDR_PROTO)
144 VRT_HDR_LR(beresp, proto, HTTP_HDR_PROTO)
145 VRT_HDR_LR(beresp, reason, HTTP_HDR_REASON)
146 VRT_STATUS_L(beresp)
147 VRT_STATUS_R(beresp)
148
149 /*--------------------------------------------------------------------
150 * Pulling things out of the packed object->http
151 */
152
153 VCL_INT
154 VRT_r_obj_status(VRT_CTX)
155 {
156 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
157 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
158 CHECK_OBJ_NOTNULL(ctx->req->objcore, OBJCORE_MAGIC);
159
160 return (HTTP_GetStatusPack(ctx->req->wrk, ctx->req->objcore));
161 }
162
163 VCL_STRING
VRT_r_obj_proto(VRT_CTX)164 VRT_r_obj_proto(VRT_CTX)
165 {
166 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
167 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
168 CHECK_OBJ_NOTNULL(ctx->req->objcore, OBJCORE_MAGIC);
169
170 return (HTTP_GetHdrPack(ctx->req->wrk, ctx->req->objcore,
171 H__Proto));
172 }
173
174 VCL_STRING
VRT_r_obj_reason(VRT_CTX)175 VRT_r_obj_reason(VRT_CTX)
176 {
177 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
178 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
179 CHECK_OBJ_NOTNULL(ctx->req->objcore, OBJCORE_MAGIC);
180
181 return (HTTP_GetHdrPack(ctx->req->wrk, ctx->req->objcore,
182 H__Reason));
183 }
184
185 /*--------------------------------------------------------------------
186 * bool-fields (.do_*)
187 */
188
189 static inline int
beresp_filter_fixed(VRT_CTX,const char * s)190 beresp_filter_fixed(VRT_CTX, const char *s)
191 {
192 if (ctx->bo->vfp_filter_list == NULL)
193 return (0);
194 VRT_fail(ctx,
195 "beresp.filters are already fixed, beresp.%s is undefined", s);
196 return (1);
197 }
198
199 #define VBERESPWF0(ctx, str) (void) 0
200 #define VBERESPWF1(ctx, str) do { \
201 if (beresp_filter_fixed((ctx), str)) \
202 return; \
203 } while(0)
204
205 #define VBERESPW0(field, str, fltchk)
206 #define VBERESPW1(field, str, fltchk) \
207 void \
208 VRT_l_beresp_##field(VRT_CTX, VCL_BOOL a) \
209 { \
210 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
211 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC); \
212 VBERESPWF##fltchk(ctx, str); \
213 ctx->bo->field = a ? 1 : 0; \
214 }
215
216 #define VBERESPRF0(ctx, str) (void) 0
217 #define VBERESPRF1(ctx, str) do { \
218 if (beresp_filter_fixed((ctx), str)) \
219 return (0); \
220 } while(0)
221
222 #define VBERESPR0(field, str, fltchk)
223 #define VBERESPR1(field, str, fltchk) \
224 VCL_BOOL \
225 VRT_r_beresp_##field(VRT_CTX) \
226 { \
227 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
228 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC); \
229 VBERESPRF##fltchk(ctx, str); \
230 return (ctx->bo->field); \
231 }
232
233 #define VBEREQR0(field, str, fltchk)
234 #define VBEREQR1(field, str, fltchk) \
235 VCL_BOOL \
236 VRT_r_bereq_##field(VRT_CTX) \
237 { \
238 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
239 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC); \
240 return (ctx->bo->field); \
241 }
242
243 #define BO_FLAG(l, r, rr, rw, f, d) \
244 VBEREQR##r(l, #l, f) \
245 VBERESPR##rr(l, #l, f) \
246 VBERESPW##rw(l, #l, f)
247 #include "tbl/bo_flags.h"
248
249 #undef VBERESPWF0
250 #undef VBERESPWF1
251 #undef VBERESPW0
252 #undef VBERESPW1
253
254 #undef VBERESPRF0
255 #undef VBERESPRF1
256 #undef VBERESPR0
257 #undef VBERESPR1
258 /*--------------------------------------------------------------------*/
259
260 VCL_BOOL
VRT_r_bereq_uncacheable(VRT_CTX)261 VRT_r_bereq_uncacheable(VRT_CTX)
262 {
263 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
264 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
265 return (ctx->bo->do_pass);
266 }
267
268 VCL_VOID
VRT_l_beresp_uncacheable(VRT_CTX,VCL_BOOL a)269 VRT_l_beresp_uncacheable(VRT_CTX, VCL_BOOL a)
270 {
271 struct objcore *oc;
272
273 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
274 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
275 CHECK_OBJ_NOTNULL(ctx->bo->fetch_objcore, OBJCORE_MAGIC);
276
277 if (ctx->bo->uncacheable && !a) {
278 VSLb(ctx->vsl, SLT_VCL_Error,
279 "Ignoring attempt to reset beresp.uncacheable");
280 } else if (a) {
281 ctx->bo->uncacheable = 1;
282 }
283 oc = ctx->bo->fetch_objcore;
284
285 VSLb(ctx->vsl, SLT_TTL, "VCL %.0f %.0f %.0f %.0f %s", \
286 oc->ttl, oc->grace, oc->keep, oc->t_origin, \
287 ctx->bo->uncacheable ? "uncacheable" : "cacheable");\
288 }
289
290 VCL_BOOL
VRT_r_beresp_uncacheable(VRT_CTX)291 VRT_r_beresp_uncacheable(VRT_CTX)
292 {
293 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
294 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
295 return (ctx->bo->uncacheable);
296 }
297
298 /*--------------------------------------------------------------------*/
299
300 VCL_STRING
VRT_r_client_identity(VRT_CTX)301 VRT_r_client_identity(VRT_CTX)
302 {
303 const char *id;
304
305 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
306 if (ctx->req != NULL) {
307 CHECK_OBJ(ctx->req, REQ_MAGIC);
308 id = ctx->req->client_identity;
309 } else {
310 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
311 id = ctx->bo->client_identity;
312 }
313 if (id != NULL)
314 return (id);
315 return (SES_Get_String_Attr(ctx->sp, SA_CLIENT_IP));
316 }
317
318 VCL_VOID
VRT_l_client_identity(VRT_CTX,const char * str,...)319 VRT_l_client_identity(VRT_CTX, const char *str, ...)
320 {
321 va_list ap;
322 const char *b;
323
324 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
325 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
326 va_start(ap, str);
327 b = VRT_String(ctx->req->http->ws, NULL, str, ap);
328 va_end(ap);
329 if (b == NULL) {
330 VSLb(ctx->vsl, SLT_LostHeader, "client.identity");
331 WS_MarkOverflow(ctx->req->http->ws);
332 return;
333 }
334 ctx->req->client_identity = b;
335 }
336
337 /*--------------------------------------------------------------------*/
338
339 #define BEREQ_TIMEOUT(which) \
340 VCL_VOID \
341 VRT_l_bereq_##which(VRT_CTX, VCL_DURATION num) \
342 { \
343 \
344 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
345 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC); \
346 ctx->bo->which = (num > 0.0 ? num : 0.0); \
347 } \
348 \
349 VCL_DURATION \
350 VRT_r_bereq_##which(VRT_CTX) \
351 { \
352 \
353 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
354 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC); \
355 return (ctx->bo->which); \
356 }
357
358 BEREQ_TIMEOUT(connect_timeout)
BEREQ_TIMEOUT(first_byte_timeout)359 BEREQ_TIMEOUT(first_byte_timeout)
360 BEREQ_TIMEOUT(between_bytes_timeout)
361
362 /*--------------------------------------------------------------------*/
363
364 VCL_STRING
365 VRT_r_beresp_backend_name(VRT_CTX)
366 {
367
368 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
369 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
370 if (ctx->bo->director_resp != NULL)
371 return (ctx->bo->director_resp->vcl_name);
372 return (NULL);
373 }
374
375 /*--------------------------------------------------------------------
376 * Backends do not in general have a IP number (any more) and this
377 * variable is really not about the backend, but the backend connection.
378 * XXX: we may need a more general beresp.backend.{details|ident}
379 */
380
381 VCL_IP
VRT_r_beresp_backend_ip(VRT_CTX)382 VRT_r_beresp_backend_ip(VRT_CTX)
383 {
384
385 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
386 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
387 return (VDI_GetIP(ctx->bo));
388 }
389
390 /*--------------------------------------------------------------------*/
391
392 VCL_STEVEDORE
VRT_r_req_storage(VRT_CTX)393 VRT_r_req_storage(VRT_CTX)
394 {
395 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
396 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
397 return (ctx->req->storage);
398 }
399
400 VCL_VOID
VRT_l_req_storage(VRT_CTX,VCL_STEVEDORE stv)401 VRT_l_req_storage(VRT_CTX, VCL_STEVEDORE stv)
402 {
403 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
404 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
405 ctx->req->storage = stv;
406 }
407
408 /*--------------------------------------------------------------------*/
409
410 VCL_STEVEDORE
VRT_r_beresp_storage(VRT_CTX)411 VRT_r_beresp_storage(VRT_CTX)
412 {
413 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
414 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
415 return (ctx->bo->storage);
416 }
417
418 VCL_VOID
VRT_l_beresp_storage(VRT_CTX,VCL_STEVEDORE stv)419 VRT_l_beresp_storage(VRT_CTX, VCL_STEVEDORE stv)
420 {
421 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
422 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
423 ctx->bo->storage = stv;
424 }
425
426 /*--------------------------------------------------------------------
427 * VCL <= 4.0 ONLY
428 */
429
430 #include "storage/storage.h"
431
432 VCL_STRING
VRT_r_beresp_storage_hint(VRT_CTX)433 VRT_r_beresp_storage_hint(VRT_CTX)
434 {
435 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
436 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
437 if (ctx->bo->storage == NULL)
438 return (NULL);
439 CHECK_OBJ_NOTNULL(ctx->bo->storage, STEVEDORE_MAGIC);
440 return (ctx->bo->storage->vclname);
441 }
442
443 VCL_VOID
VRT_l_beresp_storage_hint(VRT_CTX,const char * str,...)444 VRT_l_beresp_storage_hint(VRT_CTX, const char *str, ...)
445 {
446 const char *p;
447 va_list ap;
448 uintptr_t sn;
449 VCL_STEVEDORE stv;
450
451 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
452 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
453
454 sn = WS_Snapshot(ctx->ws);
455 va_start(ap, str);
456 p = VRT_String(ctx->ws, NULL, str, ap);
457 va_end(ap);
458
459 if (p == NULL) {
460 VSLb(ctx->vsl, SLT_LostHeader, "storage_hint");
461 WS_Reset(ctx->ws, sn);
462 WS_MarkOverflow(ctx->ws);
463 return;
464 }
465
466 stv = VRT_stevedore(p);
467 if (stv != NULL)
468 ctx->bo->storage = stv;
469
470 WS_Reset(ctx->ws, sn);
471 }
472
473 /*--------------------------------------------------------------------*/
474
475 VCL_STEVEDORE
VRT_r_obj_storage(VRT_CTX)476 VRT_r_obj_storage(VRT_CTX)
477 {
478 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
479 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
480 CHECK_OBJ_NOTNULL(ctx->req->objcore, OBJCORE_MAGIC);
481 AN(ctx->req->objcore->stobj);
482 CHECK_OBJ_NOTNULL(ctx->req->objcore->stobj->stevedore,
483 STEVEDORE_MAGIC);
484 return (ctx->req->objcore->stobj->stevedore);
485 }
486
487 /*--------------------------------------------------------------------*/
488
489 VCL_BOOL
VRT_r_obj_can_esi(VRT_CTX)490 VRT_r_obj_can_esi(VRT_CTX)
491 {
492 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
493 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
494 CHECK_OBJ_NOTNULL(ctx->req->objcore, OBJCORE_MAGIC);
495 return (ObjHasAttr(ctx->req->wrk, ctx->req->objcore, OA_ESIDATA));
496 }
497
498 /*--------------------------------------------------------------------*/
499
500 #define REQ_VAR_L(nm, elem, type, extra) \
501 \
502 VCL_VOID \
503 VRT_l_req_##nm(VRT_CTX, type arg) \
504 { \
505 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
506 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC); \
507 extra; \
508 ctx->req->elem = arg; \
509 }
510
511 #define REQ_VAR_R(nm, elem, type) \
512 \
513 type \
514 VRT_r_req_##nm(VRT_CTX) \
515 { \
516 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
517 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC); \
518 return (ctx->req->elem); \
519 }
520
521 REQ_VAR_L(backend_hint, director_hint, VCL_BACKEND,)
REQ_VAR_R(backend_hint,director_hint,VCL_BACKEND)522 REQ_VAR_R(backend_hint, director_hint, VCL_BACKEND)
523 REQ_VAR_L(ttl, d_ttl, VCL_DURATION, if (!(arg>0.0)) arg = 0;)
524 REQ_VAR_R(ttl, d_ttl, VCL_DURATION)
525 REQ_VAR_L(grace, d_grace, VCL_DURATION, if (!(arg>0.0)) arg = 0;)
526 REQ_VAR_R(grace, d_grace, VCL_DURATION)
527
528 /*--------------------------------------------------------------------*/
529
530 VCL_VOID
531 VRT_l_bereq_backend(VRT_CTX, VCL_BACKEND be)
532 {
533
534 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
535 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
536 ctx->bo->director_req = be;
537 }
538
539 VCL_BACKEND
VRT_r_bereq_backend(VRT_CTX)540 VRT_r_bereq_backend(VRT_CTX)
541 {
542
543 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
544 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
545 return (ctx->bo->director_req);
546 }
547
548 VCL_BACKEND
VRT_r_beresp_backend(VRT_CTX)549 VRT_r_beresp_backend(VRT_CTX)
550 {
551
552 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
553 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
554 return (ctx->bo->director_resp);
555 }
556
557 /*--------------------------------------------------------------------*/
558
559 VCL_VOID
VRT_u_bereq_body(VRT_CTX)560 VRT_u_bereq_body(VRT_CTX)
561 {
562 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
563 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
564 if (ctx->bo->req != NULL) {
565 CHECK_OBJ(ctx->bo->req, REQ_MAGIC);
566 ctx->bo->req = NULL;
567 ObjSetState(ctx->bo->wrk,
568 ctx->bo->fetch_objcore, BOS_REQ_DONE);
569 http_Unset(ctx->bo->bereq, H_Content_Length);
570 }
571 }
572
573 /*--------------------------------------------------------------------*/
574
575 VCL_VOID
VRT_l_req_esi(VRT_CTX,VCL_BOOL process_esi)576 VRT_l_req_esi(VRT_CTX, VCL_BOOL process_esi)
577 {
578
579 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
580 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
581 assert(ctx->syntax <= 40);
582 /*
583 * Only allow you to turn of esi in the main request
584 * else everything gets confused
585 * NOTE: this is not true, but we do not change behavior
586 * for vcl 4.0. For 4.1, see VRT_l_resp_do_esi()
587 */
588 if (IS_TOPREQ(ctx->req))
589 ctx->req->disable_esi = !process_esi;
590 }
591
592 VCL_BOOL
VRT_r_req_esi(VRT_CTX)593 VRT_r_req_esi(VRT_CTX)
594 {
595
596 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
597 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
598 assert(ctx->syntax <= 40);
599 return (!ctx->req->disable_esi);
600 }
601
602 VCL_INT
VRT_r_req_esi_level(VRT_CTX)603 VRT_r_req_esi_level(VRT_CTX)
604 {
605
606 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
607 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
608 return (ctx->req->esi_level);
609 }
610
611 /*--------------------------------------------------------------------*/
612
613 VCL_BOOL
VRT_r_req_can_gzip(VRT_CTX)614 VRT_r_req_can_gzip(VRT_CTX)
615 {
616
617 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
618 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
619 return (RFC2616_Req_Gzip(ctx->req->http)); // XXX ?
620 }
621
622 /*--------------------------------------------------------------------*/
623
624 VCL_INT
VRT_r_req_restarts(VRT_CTX)625 VRT_r_req_restarts(VRT_CTX)
626 {
627
628 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
629 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
630 return (ctx->req->restarts);
631 }
632
633 VCL_INT
VRT_r_bereq_retries(VRT_CTX)634 VRT_r_bereq_retries(VRT_CTX)
635 {
636
637 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
638 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
639 return (ctx->bo->retries);
640 }
641
642 /*--------------------------------------------------------------------
643 * In exp.*:
644 * t_origin is absolute
645 * ttl is relative to t_origin
646 * grace&keep are relative to ttl
647 * In VCL:
648 * ttl is relative to "ttl_now", which is t_req on the client
649 * side, except in vcl_deliver, where it is ctx->now. On the
650 * fetch side "ttl_now" is ctx->now (which is bo->t_prev).
651 * grace&keep are relative to ttl
652 */
653
654 static double
ttl_now(VRT_CTX)655 ttl_now(VRT_CTX)
656 {
657 if (ctx->bo) {
658 return (ctx->now);
659 } else {
660 CHECK_OBJ(ctx->req, REQ_MAGIC);
661 return (ctx->method == VCL_MET_DELIVER
662 ? ctx->now : ctx->req->t_req);
663 }
664 }
665
666 #define VRT_DO_EXP_L(which, oc, fld, offset) \
667 \
668 VCL_VOID \
669 VRT_l_##which##_##fld(VRT_CTX, VCL_DURATION a) \
670 { \
671 \
672 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
673 a += (offset); \
674 if (a < 0.0) \
675 a = 0.0; \
676 oc->fld = a; \
677 VSLb(ctx->vsl, SLT_TTL, "VCL %.0f %.0f %.0f %.0f %s", \
678 oc->ttl, oc->grace, oc->keep, oc->t_origin, \
679 ctx->bo->uncacheable ? "uncacheable" : "cacheable");\
680 }
681
682 #define VRT_DO_EXP_R(which, oc, fld, offset) \
683 \
684 VCL_DURATION \
685 VRT_r_##which##_##fld(VRT_CTX) \
686 { \
687 double d; \
688 \
689 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
690 d = oc->fld; \
691 if (d <= 0.0) \
692 d = 0.0; \
693 d -= (offset); \
694 return (d); \
695 }
696
697 /*lint -save -e835 */ // Zero right hand arg to '-'
698
699 VRT_DO_EXP_R(obj, ctx->req->objcore, ttl,
700 ttl_now(ctx) - ctx->req->objcore->t_origin)
701 VRT_DO_EXP_R(obj, ctx->req->objcore, grace, 0)
702 VRT_DO_EXP_R(obj, ctx->req->objcore, keep, 0)
703 VRT_DO_EXP_L(beresp, ctx->bo->fetch_objcore, ttl,
704 ttl_now(ctx) - ctx->bo->fetch_objcore->t_origin)
705 VRT_DO_EXP_R(beresp, ctx->bo->fetch_objcore, ttl,
706 ttl_now(ctx) - ctx->bo->fetch_objcore->t_origin)
707
708 VRT_DO_EXP_L(beresp, ctx->bo->fetch_objcore, grace, 0)
709 VRT_DO_EXP_R(beresp, ctx->bo->fetch_objcore, grace, 0)
710 VRT_DO_EXP_L(beresp, ctx->bo->fetch_objcore, keep, 0)
711 VRT_DO_EXP_R(beresp, ctx->bo->fetch_objcore, keep, 0)
712
713 /*lint -restore */
714
715 /*--------------------------------------------------------------------
716 */
717
718 #define VRT_DO_AGE_R(which, oc) \
719 \
720 VCL_DURATION \
721 VRT_r_##which##_##age(VRT_CTX) \
722 { \
723 \
724 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
725 return (ttl_now(ctx) - oc->t_origin); \
726 }
727
728 VRT_DO_AGE_R(obj, ctx->req->objcore)
729 VRT_DO_AGE_R(beresp, ctx->bo->fetch_objcore)
730
731 /*--------------------------------------------------------------------
732 * [[be]req|sess].xid
733 */
734
735 VCL_STRING
VRT_r_req_xid(VRT_CTX)736 VRT_r_req_xid(VRT_CTX)
737 {
738
739 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
740 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
741 CHECK_OBJ_NOTNULL(ctx->req->http, HTTP_MAGIC);
742 AN(ctx->req->vsl);
743
744 return (WS_Printf(ctx->req->http->ws, "%u",
745 VXID(ctx->req->vsl->wid)));
746 }
747
748 VCL_STRING
VRT_r_bereq_xid(VRT_CTX)749 VRT_r_bereq_xid(VRT_CTX)
750 {
751
752 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
753 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
754 AN(ctx->bo->vsl);
755
756 return (WS_Printf(ctx->ws, "%u", VXID(ctx->bo->vsl->wid)));
757 }
758
759 VCL_STRING
VRT_r_sess_xid(VRT_CTX)760 VRT_r_sess_xid(VRT_CTX)
761 {
762 struct sess *sp;
763
764 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
765
766 if (ctx->req) {
767 CHECK_OBJ(ctx->req, REQ_MAGIC);
768 sp = ctx->req->sp;
769 } else {
770 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
771 sp = ctx->bo->sp;
772 }
773
774 CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
775 return (WS_Printf(ctx->ws, "%u", VXID(sp->vxid)));
776 }
777
778 /*--------------------------------------------------------------------
779 * req fields
780 */
781
782 #define VREQW0(field)
783 #define VREQW1(field) \
784 VCL_VOID \
785 VRT_l_req_##field(VRT_CTX, VCL_BOOL a) \
786 { \
787 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
788 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC); \
789 ctx->req->field = a ? 1 : 0; \
790 }
791
792 #define VREQR0(field)
793 #define VREQR1(field) \
794 VCL_BOOL \
795 VRT_r_req_##field(VRT_CTX) \
796 { \
797 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
798 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC); \
799 return (ctx->req->field); \
800 }
801
802 #define REQ_FLAG(l, r, w, d) \
803 VREQR##r(l) \
804 VREQW##w(l)
805 #include "tbl/req_flags.h"
806
807 /*--------------------------------------------------------------------*/
808
809 #define GIP(fld) \
810 VCL_IP \
811 VRT_r_##fld##_ip(VRT_CTX) \
812 { \
813 struct suckaddr *sa; \
814 \
815 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
816 CHECK_OBJ_NOTNULL(ctx->sp, SESS_MAGIC); \
817 AZ(SES_Get_##fld##_addr(ctx->sp, &sa)); \
818 return (sa); \
819 }
820
821 GIP(local)
GIP(remote)822 GIP(remote)
823 GIP(client)
824 GIP(server)
825 #undef GIP
826
827 /*--------------------------------------------------------------------
828 * local.[endpoint|socket]
829 */
830
831 #define LOC(var,fld) \
832 VCL_STRING \
833 VRT_r_local_##var(VRT_CTX) \
834 { \
835 struct sess *sp; \
836 \
837 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
838 if (ctx->req) { \
839 CHECK_OBJ(ctx->req, REQ_MAGIC); \
840 sp = ctx->req->sp; \
841 } else { \
842 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC); \
843 sp = ctx->bo->sp; \
844 } \
845 \
846 CHECK_OBJ_NOTNULL(sp->listen_sock, LISTEN_SOCK_MAGIC); \
847 AN(sp->listen_sock->fld); \
848 return (sp->listen_sock->fld); \
849 }
850
851 LOC(endpoint, endpoint)
852 LOC(socket, name)
853 #undef LOC
854
855 /*--------------------------------------------------------------------*/
856
857 VCL_STRING
858 VRT_r_server_identity(VRT_CTX)
859 {
860
861 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
862 if (heritage.identity != NULL)
863 return (heritage.identity);
864 else
865 return ("varnishd");
866 }
867
868 VCL_STRING
VRT_r_server_hostname(VRT_CTX)869 VRT_r_server_hostname(VRT_CTX)
870 {
871
872 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
873 if (vrt_hostname[0] == '\0')
874 AZ(gethostname(vrt_hostname, sizeof(vrt_hostname)));
875 return (vrt_hostname);
876 }
877
878 /*--------------------------------------------------------------------*/
879
880 VCL_INT
VRT_r_obj_hits(VRT_CTX)881 VRT_r_obj_hits(VRT_CTX)
882 {
883 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
884 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
885 CHECK_OBJ_NOTNULL(ctx->req->objcore, OBJCORE_MAGIC);
886 if (ctx->method == VCL_MET_HIT)
887 return (ctx->req->objcore->hits);
888 return (ctx->req->is_hit ? ctx->req->objcore->hits : 0);
889 }
890
891 VCL_BOOL
VRT_r_obj_uncacheable(VRT_CTX)892 VRT_r_obj_uncacheable(VRT_CTX)
893 {
894
895 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
896 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
897 CHECK_OBJ_NOTNULL(ctx->req->objcore, OBJCORE_MAGIC);
898 return (ctx->req->objcore->flags & OC_F_HFM ? 1 : 0);
899 }
900
901 /*--------------------------------------------------------------------*/
902
903 VCL_BOOL
VRT_r_resp_is_streaming(VRT_CTX)904 VRT_r_resp_is_streaming(VRT_CTX)
905 {
906 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
907 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
908 if (ctx->req->objcore == NULL)
909 return (0); /* When called from vcl_synth */
910 CHECK_OBJ_NOTNULL(ctx->req->objcore, OBJCORE_MAGIC);
911 return (ctx->req->objcore->boc == NULL ? 0 : 1);
912 }
913
914 /*--------------------------------------------------------------------*/
915
916 static inline int
resp_filter_fixed(VRT_CTX,const char * s)917 resp_filter_fixed(VRT_CTX, const char *s)
918 {
919 if (ctx->req->filter_list == NULL)
920 return (0);
921 VRT_fail(ctx, "resp.filters are already fixed, %s is undefined", s);
922 return (1);
923 }
924
925 VCL_VOID
VRT_l_resp_do_esi(VRT_CTX,VCL_BOOL process_esi)926 VRT_l_resp_do_esi(VRT_CTX, VCL_BOOL process_esi)
927 {
928
929 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
930 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
931 assert(ctx->syntax >= 41);
932 if (resp_filter_fixed(ctx, "resp.do_esi"))
933 return;
934 ctx->req->disable_esi = !process_esi;
935 }
936
937 VCL_BOOL
VRT_r_resp_do_esi(VRT_CTX)938 VRT_r_resp_do_esi(VRT_CTX)
939 {
940
941 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
942 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
943 assert(ctx->syntax >= 41);
944 if (resp_filter_fixed(ctx, "resp.do_esi"))
945 return (0);
946 return (!ctx->req->disable_esi);
947 }
948
949 /*--------------------------------------------------------------------*/
950
951 #define VRT_BODY_L(which) \
952 VCL_VOID \
953 VRT_l_##which##_body(VRT_CTX, enum lbody_e type, \
954 const char *str, ...) \
955 { \
956 va_list ap; \
957 const char *p; \
958 struct vsb *vsb; \
959 \
960 CAST_OBJ_NOTNULL(vsb, ctx->specific, VSB_MAGIC); \
961 assert(type == LBODY_SET || type == LBODY_ADD); \
962 if (type == LBODY_SET) \
963 VSB_clear(vsb); \
964 va_start(ap, str); \
965 p = str; \
966 while (p != vrt_magic_string_end) { \
967 if (p == NULL) \
968 p = "(null)"; \
969 VSB_cat(vsb, p); \
970 p = va_arg(ap, const char *); \
971 } \
972 va_end(ap); \
973 }
974
975 VRT_BODY_L(beresp)
VRT_BODY_L(resp)976 VRT_BODY_L(resp)
977
978 /*--------------------------------------------------------------------*/
979
980 /* digest */
981 #define BLOB_HASH_TYPE 0x00d16357
982
983 VCL_BLOB
984 VRT_r_req_hash(VRT_CTX)
985 {
986 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
987 CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
988 return (VRT_blob(ctx, "req.hash", ctx->req->digest, DIGEST_LEN,
989 BLOB_HASH_TYPE));
990 }
991
992 VCL_BLOB
VRT_r_bereq_hash(VRT_CTX)993 VRT_r_bereq_hash(VRT_CTX)
994 {
995 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
996 CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
997 return (VRT_blob(ctx, "bereq.hash", ctx->bo->digest, DIGEST_LEN,
998 BLOB_HASH_TYPE));
999 }
1000
1001 /*--------------------------------------------------------------------*/
1002
1003 #define HTTP_VAR(x) \
1004 VCL_HTTP \
1005 VRT_r_##x(VRT_CTX) \
1006 { \
1007 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
1008 CHECK_OBJ_NOTNULL(ctx->http_##x, HTTP_MAGIC); \
1009 return (ctx->http_##x); \
1010 }
1011
1012 HTTP_VAR(req)
HTTP_VAR(resp)1013 HTTP_VAR(resp)
1014 HTTP_VAR(bereq)
1015 HTTP_VAR(beresp)
1016
1017 /*--------------------------------------------------------------------*/
1018
1019 static inline void
1020 set_idle_send_timeout(const struct sess *sp, VCL_DURATION d)
1021 {
1022 #ifdef SO_SNDTIMEO_WORKS
1023 struct timeval tv = VTIM_timeval(d);
1024 VTCP_Assert(setsockopt(sp->fd, SOL_SOCKET, SO_SNDTIMEO,
1025 &tv, sizeof tv));
1026 #else
1027 (void)sp;
1028 (void)d;
1029 #endif
1030 }
1031
1032 #define SESS_VAR_DUR(x, setter) \
1033 VCL_VOID \
1034 VRT_l_sess_##x(VRT_CTX, VCL_DURATION d) \
1035 { \
1036 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
1037 CHECK_OBJ_NOTNULL(ctx->sp, SESS_MAGIC); \
1038 if (d < 0.0) \
1039 d = 0.0; \
1040 setter; \
1041 ctx->sp->x = d; \
1042 } \
1043 \
1044 VCL_DURATION \
1045 VRT_r_sess_##x(VRT_CTX) \
1046 { \
1047 CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
1048 CHECK_OBJ_NOTNULL(ctx->sp, SESS_MAGIC); \
1049 return (SESS_TMO(ctx->sp, x)); \
1050 }
1051
1052 SESS_VAR_DUR(timeout_idle, )
1053 SESS_VAR_DUR(timeout_linger, )
1054 SESS_VAR_DUR(send_timeout, )
1055 SESS_VAR_DUR(idle_send_timeout, set_idle_send_timeout(ctx->sp, d))
1056