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