I installed Varnish with command apt-get install varnish
Varnish version is varnishd (varnish-6.2.1 revision 9f8588e4ab785244e06c3446fe09bf9db5dd8753)
I try to validate my VCL file with command varnishd -C -f /etc/varnish/default.vcl
My VCL file:
vcl 4.0;
backend default {
.host = "127.0.0.1";
.port = "8080";
}
sub vcl_recv {
}
sub vcl_backend_response {
}
sub vcl_deliver {
}
This is the response I get, seems like it just echoes out varnish .c file:
/* ---===### Location Counters ###===---*/
#define VGC_NREFS 35
static const struct vrt_ref VGC_ref[VGC_NREFS] = {
[ 1] = { 0, 796, 26, 1, "}" },
[ 2] = { 0, 1025, 33, 1, "}" },
[ 3] = { 0, 1223, 40, 1, "}" },
[ 4] = { 1, 1605, 38, 5, "if" },
[ 5] = { 1, 1719, 40, 9, "return" },
[ 6] = { 1, 1750, 42, 5, "if" },
[ 7] = { 1, 1890, 46, 9, "return" },
[ 8] = { 1, 1921, 48, 5, "if" },
[ 9] = { 1, 2225, 57, 9, "return" },
[ 10] = { 1, 2251, 60, 5, "if" },
[ 11] = { 1, 2366, 62, 9, "return" },
[ 12] = { 1, 2391, 64, 5, "if" },
[ 13] = { 1, 2487, 66, 9, "return" },
[ 14] = { 1, 2512, 68, 5, "return" },
[ 15] = { 1, 2819, 77, 5, "return" },
[ 16] = { 1, 2856, 81, 5, "return" },
[ 17] = { 1, 2894, 85, 5, "hash_data" },
[ 18] = { 1, 2947, 87, 9, "hash_data" },
[ 19] = { 1, 2994, 89, 9, "hash_data" },
[ 20] = { 1, 3066, 95, 5, "return" },
[ 21] = { 1, 3118, 99, 5, "return" },
[ 22] = { 1, 3158, 103, 5, "return" },
[ 23] = { 1, 3199, 107, 5, "return" },
[ 24] = { 1, 3316, 114, 5, "set" },
[ 25] = { 1, 3907, 138, 5, "if" },
[ 26] = { 1, 3944, 139, 9, "unset" },
[ 27] = { 1, 3972, 141, 5, "return" },
[ 28] = { 1, 4022, 145, 5, "if" },
[ 29] = { 1, 4055, 146, 9, "return" },
[ 30] = { 1, 4407, 154, 9, "set" },
[ 31] = { 1, 4479, 157, 5, "return" },
[ 32] = { 1, 4528, 161, 5, "set" },
[ 33] = { 1, 5127, 185, 5, "return" },
[ 34] = { 1, 5162, 189, 5, "return" },
};
/* ---===### VCC generated .h code ###===---*/
static struct vsmw_cluster *vsc_cluster;
extern const struct VCL_conf VCL_conf;
static VCL_BACKEND vgc_backend_default;
/* "127.0.0.1 8080" -> 127.0.0.1 */
static const unsigned long long suckaddr_0[4] = {
0x901f00024b1e9335ULL,
0x000000000100007fULL,
0x0000000000000000ULL,
0x0000000000000000ULL
};
static const struct vrt_backend vgc_dir_priv_vgc_backend_default = {
.magic = VRT_BACKEND_MAGIC,
.vcl_name = "default",
.ipv4_suckaddr = (const struct suckaddr *)(const void*)suckaddr_0,
.ipv4_addr = "127.0.0.1",
.port = "8080",
.path = (void *) 0,
.hosthdr = "127.0.0.1",
};
static const struct gethdr_s VGC_HDR_REQ_host =
{ HDR_REQ, "\005host:"};
static void *VGC_re_1;
static const struct gethdr_s VGC_HDR_REQ_Authorization =
{ HDR_REQ, "\016Authorization:"};
static const struct gethdr_s VGC_HDR_REQ_Cookie =
{ HDR_REQ, "\007Cookie:"};
static const struct gethdr_s VGC_HDR_RESP_Content_2d_Type =
{ HDR_RESP, "\015Content-Type:"};
static const struct gethdr_s VGC_HDR_RESP_Retry_2d_After =
{ HDR_RESP, "\014Retry-After:"};
static const struct gethdr_s VGC_HDR_BERESP_Set_2d_Cookie =
{ HDR_BERESP, "\013Set-Cookie:"};
static const struct gethdr_s VGC_HDR_BERESP_Surrogate_2d_control =
{ HDR_BERESP, "\022Surrogate-control:"};
static void *VGC_re_2;
static const struct gethdr_s VGC_HDR_BERESP_Cache_2d_Control =
{ HDR_BERESP, "\016Cache-Control:"};
static void *VGC_re_3;
static const struct gethdr_s VGC_HDR_BERESP_Vary =
{ HDR_BERESP, "\005Vary:"};
static const struct gethdr_s VGC_HDR_BERESP_Content_2d_Type =
{ HDR_BERESP, "\015Content-Type:"};
static const struct gethdr_s VGC_HDR_BERESP_Retry_2d_After =
{ HDR_BERESP, "\014Retry-After:"};
vcl_func_f VGC_function_vcl_backend_error;
vcl_func_f VGC_function_vcl_backend_fetch;
vcl_func_f VGC_function_vcl_backend_response;
vcl_func_f VGC_function_vcl_deliver;
vcl_func_f VGC_function_vcl_fini;
vcl_func_f VGC_function_vcl_hash;
vcl_func_f VGC_function_vcl_hit;
vcl_func_f VGC_function_vcl_init;
vcl_func_f VGC_function_vcl_miss;
vcl_func_f VGC_function_vcl_pass;
vcl_func_f VGC_function_vcl_pipe;
vcl_func_f VGC_function_vcl_purge;
vcl_func_f VGC_function_vcl_recv;
vcl_func_f VGC_function_vcl_synth;
static unsigned vgc_inistep;
static unsigned vgc_warmupstep;
/* ---===### VCC generated .c code ###===---*/
#define END_ if (*ctx->handling) return
void v_matchproto_(vcl_func_f)
VGC_function_vcl_backend_error(VRT_CTX)
{
/* ... from ('Builtin' Line 160 Pos 23) */
{
{
VRT_count(ctx, 32);
END_;
VRT_SetHdr(ctx, &VGC_HDR_BERESP_Content_2d_Type,
"text/html; charset=utf-8",
vrt_magic_string_end
);
END_;
VRT_SetHdr(ctx, &VGC_HDR_BERESP_Retry_2d_After,
"5",
vrt_magic_string_end
);
END_;
VRT_l_beresp_body(ctx,
"<!DOCTYPE html>\n"
"<html>\n"
" <head>\n"
" <title>",
VRT_INT_string(ctx, VRT_r_beresp_status(ctx)),
" ",
VRT_r_beresp_reason(ctx),
"</title>\n"
" </head>\n"
" <body>\n"
" <h1>Error ",
VRT_INT_string(ctx, VRT_r_beresp_status(ctx)),
" ",
VRT_r_beresp_reason(ctx),
"</h1>\n"
" <p>",
VRT_r_beresp_reason(ctx),
"</p>\n"
" <h3>Guru Meditation:</h3>\n"
" <p>XID: ",
VRT_r_bereq_xid(ctx),
"</p>\n"
" <hr>\n"
" <p>Varnish cache server</p>\n"
" </body>\n"
"</html>\n"
"",
vrt_magic_string_end
);
END_;
VRT_handling(ctx, VCL_RET_DELIVER);
END_;
}
}
}
void v_matchproto_(vcl_func_f)
VGC_function_vcl_backend_fetch(VRT_CTX)
{
/* ... from ('Builtin' Line 137 Pos 23) */
{
{
VRT_count(ctx, 25);
END_;
if (
(0 == VRT_strcmp(VRT_r_bereq_method(ctx), "GET"))
)
{
VRT_count(ctx, 26);
END_;
VRT_u_bereq_body(ctx);
END_;
}
VRT_count(ctx, 27);
END_;
VRT_handling(ctx, VCL_RET_FETCH);
END_;
}
}
}
void v_matchproto_(vcl_func_f)
VGC_function_vcl_backend_response(VRT_CTX)
{
/* ... from ('/etc/varnish/default.vcl' Line 28 Pos 26) */
{
{
VRT_count(ctx, 2);
END_;
}
}
/* ... from ('Builtin' Line 144 Pos 26) */
{
{
VRT_count(ctx, 28);
END_;
if (
VRT_r_bereq_uncacheable(ctx)
)
{
VRT_count(ctx, 29);
END_;
VRT_handling(ctx, VCL_RET_DELIVER);
END_;
}
else if (
(
(VRT_r_beresp_ttl(ctx) <= (0) * 1)
||
(VRT_GetHdr(ctx, &VGC_HDR_BERESP_Set_2d_Cookie) != 0)
||
VRT_re_match(ctx, VRT_GetHdr(ctx, &VGC_HDR_BERESP_Surrogate_2d_control), VGC_re_2)
||
((
!((VRT_GetHdr(ctx, &VGC_HDR_BERESP_Surrogate_2d_control) != 0))
&&
VRT_re_match(ctx, VRT_GetHdr(ctx, &VGC_HDR_BERESP_Cache_2d_Control), VGC_re_3)
))
||
(0 == VRT_strcmp(VRT_GetHdr(ctx, &VGC_HDR_BERESP_Vary), "*"))
)
)
{
VRT_count(ctx, 30);
END_;
VRT_l_beresp_ttl(ctx,
(120) * 1
);
END_;
VRT_l_beresp_uncacheable(ctx,
(0==0)
);
END_;
}
VRT_count(ctx, 31);
END_;
VRT_handling(ctx, VCL_RET_DELIVER);
END_;
}
}
}
void v_matchproto_(vcl_func_f)
VGC_function_vcl_deliver(VRT_CTX)
{
/* ... from ('/etc/varnish/default.vcl' Line 35 Pos 17) */
{
{
VRT_count(ctx, 3);
END_;
}
}
/* ... from ('Builtin' Line 106 Pos 17) */
{
{
VRT_count(ctx, 23);
END_;
VRT_handling(ctx, VCL_RET_DELIVER);
END_;
}
}
}
void v_matchproto_(vcl_func_f)
VGC_function_vcl_fini(VRT_CTX)
{
/* ... from ('Builtin' Line 188 Pos 14) */
{
{
VRT_count(ctx, 34);
END_;
VRT_handling(ctx, VCL_RET_OK);
END_;
}
}
}
void v_matchproto_(vcl_func_f)
VGC_function_vcl_hash(VRT_CTX)
{
/* ... from ('Builtin' Line 84 Pos 14) */
{
{
VRT_count(ctx, 17);
END_;
VRT_hashdata(ctx,
VRT_r_req_url(ctx),
vrt_magic_string_end
);
END_;
if (
(VRT_GetHdr(ctx, &VGC_HDR_REQ_host) != 0)
)
{
VRT_count(ctx, 18);
END_;
VRT_hashdata(ctx,
VRT_GetHdr(ctx, &VGC_HDR_REQ_host),
vrt_magic_string_end
);
END_;
}
else
{
VRT_count(ctx, 19);
END_;
VRT_hashdata(ctx,
VRT_IP_string(ctx, VRT_r_server_ip(ctx)),
vrt_magic_string_end
);
END_;
}
END_;
VRT_handling(ctx, VCL_RET_LOOKUP);
END_;
}
}
}
void v_matchproto_(vcl_func_f)
VGC_function_vcl_hit(VRT_CTX)
{
/* ... from ('Builtin' Line 98 Pos 13) */
{
{
VRT_count(ctx, 21);
END_;
VRT_handling(ctx, VCL_RET_DELIVER);
END_;
}
}
}
void v_matchproto_(vcl_func_f)
VGC_function_vcl_init(VRT_CTX)
{
/* ... from ('Builtin' Line 184 Pos 14) */
{
{
VRT_count(ctx, 33);
END_;
VRT_handling(ctx, VCL_RET_OK);
END_;
}
}
}
void v_matchproto_(vcl_func_f)
VGC_function_vcl_miss(VRT_CTX)
{
/* ... from ('Builtin' Line 102 Pos 14) */
{
{
VRT_count(ctx, 22);
END_;
VRT_handling(ctx, VCL_RET_FETCH);
END_;
}
}
}
void v_matchproto_(vcl_func_f)
VGC_function_vcl_pass(VRT_CTX)
{
/* ... from ('Builtin' Line 80 Pos 14) */
{
{
VRT_count(ctx, 16);
END_;
VRT_handling(ctx, VCL_RET_FETCH);
END_;
}
}
}
void v_matchproto_(vcl_func_f)
VGC_function_vcl_pipe(VRT_CTX)
{
/* ... from ('Builtin' Line 71 Pos 14) */
{
{
VRT_count(ctx, 15);
END_;
VRT_handling(ctx, VCL_RET_PIPE);
END_;
}
}
}
void v_matchproto_(vcl_func_f)
VGC_function_vcl_purge(VRT_CTX)
{
/* ... from ('Builtin' Line 94 Pos 15) */
{
{
VRT_count(ctx, 20);
END_;
VRT_synth(ctx,
200
,
"Purged"
);
VRT_handling(ctx, VCL_RET_SYNTH);
END_;
}
}
}
void v_matchproto_(vcl_func_f)
VGC_function_vcl_recv(VRT_CTX)
{
/* ... from ('/etc/varnish/default.vcl' Line 21 Pos 14) */
{
{
VRT_count(ctx, 1);
END_;
}
}
/* ... from ('Builtin' Line 37 Pos 14) */
{
{
VRT_count(ctx, 4);
END_;
if (
(0 == VRT_strcmp(VRT_r_req_method(ctx), "PRI"))
)
{
VRT_count(ctx, 5);
END_;
VRT_synth(ctx,
405
,
(const char*)0
);
VRT_handling(ctx, VCL_RET_SYNTH);
END_;
}
VRT_count(ctx, 6);
END_;
if (
(
!((VRT_GetHdr(ctx, &VGC_HDR_REQ_host) != 0))
&&
(VRT_r_req_esi_level(ctx) == 0)
&&
VRT_re_match(ctx, VRT_r_req_proto(ctx), VGC_re_1)
)
)
{
VRT_count(ctx, 7);
END_;
VRT_synth(ctx,
400
,
(const char*)0
);
VRT_handling(ctx, VCL_RET_SYNTH);
END_;
}
VRT_count(ctx, 8);
END_;
if (
(
(0 != VRT_strcmp(VRT_r_req_method(ctx), "GET"))
&&
(0 != VRT_strcmp(VRT_r_req_method(ctx), "HEAD"))
&&
(0 != VRT_strcmp(VRT_r_req_method(ctx), "PUT"))
&&
(0 != VRT_strcmp(VRT_r_req_method(ctx), "POST"))
&&
(0 != VRT_strcmp(VRT_r_req_method(ctx), "TRACE"))
&&
(0 != VRT_strcmp(VRT_r_req_method(ctx), "OPTIONS"))
&&
(0 != VRT_strcmp(VRT_r_req_method(ctx), "DELETE"))
&&
(0 != VRT_strcmp(VRT_r_req_method(ctx), "PATCH"))
)
)
{
VRT_count(ctx, 9);
END_;
VRT_handling(ctx, VCL_RET_PIPE);
END_;
}
VRT_count(ctx, 10);
END_;
if (
(
(0 != VRT_strcmp(VRT_r_req_method(ctx), "GET"))
&&
(0 != VRT_strcmp(VRT_r_req_method(ctx), "HEAD"))
)
)
{
VRT_count(ctx, 11);
END_;
VRT_handling(ctx, VCL_RET_PASS);
END_;
}
VRT_count(ctx, 12);
END_;
if (
(
(VRT_GetHdr(ctx, &VGC_HDR_REQ_Authorization) != 0)
||
(VRT_GetHdr(ctx, &VGC_HDR_REQ_Cookie) != 0)
)
)
{
VRT_count(ctx, 13);
END_;
VRT_handling(ctx, VCL_RET_PASS);
END_;
}
VRT_count(ctx, 14);
END_;
VRT_handling(ctx, VCL_RET_HASH);
END_;
}
}
}
void v_matchproto_(vcl_func_f)
VGC_function_vcl_synth(VRT_CTX)
{
/* ... from ('Builtin' Line 113 Pos 15) */
{
{
VRT_count(ctx, 24);
END_;
VRT_SetHdr(ctx, &VGC_HDR_RESP_Content_2d_Type,
"text/html; charset=utf-8",
vrt_magic_string_end
);
END_;
VRT_SetHdr(ctx, &VGC_HDR_RESP_Retry_2d_After,
"5",
vrt_magic_string_end
);
END_;
VRT_l_resp_body(ctx,
"<!DOCTYPE html>\n"
"<html>\n"
" <head>\n"
" <title>",
VRT_INT_string(ctx, VRT_r_resp_status(ctx)),
" ",
VRT_r_resp_reason(ctx),
"</title>\n"
" </head>\n"
" <body>\n"
" <h1>Error ",
VRT_INT_string(ctx, VRT_r_resp_status(ctx)),
" ",
VRT_r_resp_reason(ctx),
"</h1>\n"
" <p>",
VRT_r_resp_reason(ctx),
"</p>\n"
" <h3>Guru Meditation:</h3>\n"
" <p>XID: ",
VRT_r_req_xid(ctx),
"</p>\n"
" <hr>\n"
" <p>Varnish cache server</p>\n"
" </body>\n"
"</html>\n"
"",
vrt_magic_string_end
);
END_;
VRT_handling(ctx, VCL_RET_DELIVER);
END_;
}
}
}
static int
VGC_Load(VRT_CTX)
{
vgc_inistep = 0;
size_t ndirector = 1UL;
/* 1 */
vsc_cluster = VRT_VSM_Cluster_New(ctx,
ndirector * VRT_backend_vsm_need(ctx));
if (vsc_cluster == 0)
return(1);
vgc_inistep = 1;
/* 2 */
vgc_backend_default =
VRT_new_backend_clustered(ctx, vsc_cluster,
&vgc_dir_priv_vgc_backend_default);
vgc_inistep = 2;
/* 3 */
VRT_re_init(&VGC_re_1, "^(\?i)HTTP/1.1");
vgc_inistep = 3;
/* 4 */
VRT_re_init(&VGC_re_2, "(\?i)no-store");
vgc_inistep = 4;
/* 5 */
VRT_re_init(&VGC_re_3, "(\?i:no-cache|no-store|private)");
vgc_inistep = 5;
/* 6 */
VGC_function_vcl_init(ctx);
vgc_inistep = 6;
if (*ctx->handling != VCL_RET_OK)
return(1);
return(0);
}
static int
VGC_Discard(VRT_CTX)
{
switch (vgc_inistep) {
case 6:
VGC_function_vcl_fini(ctx);
/* FALLTHROUGH */
case 5:
VRT_re_fini(VGC_re_3);
/* FALLTHROUGH */
case 4:
VRT_re_fini(VGC_re_2);
/* FALLTHROUGH */
case 3:
VRT_re_fini(VGC_re_1);
/* FALLTHROUGH */
case 2:
VRT_delete_backend(ctx, &vgc_backend_default);
/* FALLTHROUGH */
case 1:
VRT_VSM_Cluster_Destroy(ctx, &vsc_cluster);
/* FALLTHROUGH */
default:
break;
}
switch (vgc_inistep) {
case 6:
/* FALLTHROUGH */
case 5:
/* FALLTHROUGH */
case 4:
/* FALLTHROUGH */
case 3:
/* FALLTHROUGH */
case 2:
/* FALLTHROUGH */
case 1:
/* FALLTHROUGH */
default:
break;
}
return (0);
}
static int
VGC_Event(VRT_CTX, enum vcl_event_e ev)
{
if (ev == VCL_EVENT_LOAD)
return (VGC_Load(ctx));
if (ev == VCL_EVENT_DISCARD)
return (VGC_Discard(ctx));
(void)vgc_warmupstep;
return (0);
}
const struct VCL_conf VCL_conf = {
.magic = VCL_CONF_MAGIC,
.syntax = 40,
.event_vcl = VGC_Event,
.default_director = &vgc_backend_default,
.ref = VGC_ref,
.nref = VGC_NREFS,
.nsrc = VGC_NSRCS,
.srcname = srcname,
.srcbody = srcbody,
.nvmod = 0,
.backend_error_func = VGC_function_vcl_backend_error,
.backend_fetch_func = VGC_function_vcl_backend_fetch,
.backend_response_func = VGC_function_vcl_backend_response,
.deliver_func = VGC_function_vcl_deliver,
.fini_func = VGC_function_vcl_fini,
.hash_func = VGC_function_vcl_hash,
.hit_func = VGC_function_vcl_hit,
.init_func = VGC_function_vcl_init,
.miss_func = VGC_function_vcl_miss,
.pass_func = VGC_function_vcl_pass,
.pipe_func = VGC_function_vcl_pipe,
.purge_func = VGC_function_vcl_purge,
.recv_func = VGC_function_vcl_recv,
.synth_func = VGC_function_vcl_synth,
};
/*
* Symbol Table
*
* none VOID 41 41 acl
* none VOID 41 41 backend
* action VOID 40 41 ban
* var HTTP 0 99 bereq
* var BACKEND 0 99 bereq.backend
* var DURATION 0 99 bereq.between_bytes_timeout
* var BODY 0 99 bereq.body
* var DURATION 0 99 bereq.connect_timeout
* var DURATION 0 99 bereq.first_byte_timeout
* var BLOB 0 99 bereq.hash
* none HEADER 0 99 bereq.http*
* var BOOL 0 99 bereq.is_bgfetch
* var STRING 0 99 bereq.method
* var STRING 0 40 bereq.proto
* var STRING 41 99 bereq.proto
* var INT 0 99 bereq.retries
* var BOOL 0 99 bereq.uncacheable
* var STRING 0 99 bereq.url
* var STRING 0 99 bereq.xid
* var HTTP 0 99 beresp
* var DURATION 0 99 beresp.age
* var BACKEND 0 99 beresp.backend
* var IP 0 40 beresp.backend.ip
* var STRING 0 99 beresp.backend.name
* var BODY 0 99 beresp.body
* var BOOL 0 99 beresp.do_esi
* var BOOL 0 99 beresp.do_gunzip
* var BOOL 0 99 beresp.do_gzip
* var BOOL 0 99 beresp.do_stream
* var STRING 0 99 beresp.filters
* var DURATION 0 99 beresp.grace
* none HEADER 0 99 beresp.http*
* var HEADER 40 40 beresp.http.Cache-Control
* var HEADER 40 40 beresp.http.Content-Type
* var HEADER 40 40 beresp.http.Retry-After
* var HEADER 40 40 beresp.http.Set-Cookie
* var HEADER 40 40 beresp.http.Surrogate-control
* var HEADER 40 40 beresp.http.Vary
* var DURATION 0 99 beresp.keep
* var STRING 0 40 beresp.proto
* var STRING 41 99 beresp.proto
* var STRING 0 99 beresp.reason
* var INT 0 99 beresp.status
* var STEVEDORE 0 99 beresp.storage
* var STRING 0 40 beresp.storage_hint
* var DURATION 0 99 beresp.ttl
* var BOOL 0 99 beresp.uncacheable
* var BOOL 0 99 beresp.was_304
* action VOID 40 41 call
* none VOID 0 99 client
* var STRING 0 99 client.identity
* var IP 0 99 client.ip
* none VOID 41 41 default
* func BOOL 40 41 false
* action VOID 40 41 hash_data
* action VOID 40 41 if
* none VOID 41 41 import
* none VOID 0 99 local
* var STRING 41 99 local.endpoint
* var IP 0 99 local.ip
* var STRING 41 99 local.socket
* action VOID 40 41 new
* var TIME 0 99 now
* none VOID 0 99 obj
* var DURATION 0 99 obj.age
* var DURATION 0 99 obj.grace
* var INT 0 99 obj.hits
* none HEADER 0 99 obj.http*
* var DURATION 0 99 obj.keep
* var STRING 0 99 obj.proto
* var STRING 0 99 obj.reason
* var INT 0 99 obj.status
* var STEVEDORE 0 99 obj.storage
* var DURATION 0 99 obj.ttl
* var BOOL 0 99 obj.uncacheable
* none VOID 41 41 probe
* func STRING 40 41 regsub
* func STRING 40 41 regsuball
* none VOID 0 99 remote
* var IP 0 99 remote.ip
* var HTTP 0 99 req
* var BACKEND 0 99 req.backend_hint
* var BOOL 0 99 req.can_gzip
* var BOOL 0 40 req.esi
* var INT 0 99 req.esi_level
* var DURATION 0 99 req.grace
* var BLOB 0 99 req.hash
* var BOOL 0 99 req.hash_always_miss
* var BOOL 0 99 req.hash_ignore_busy
* none HEADER 0 99 req.http*
* var HEADER 40 40 req.http.Authorization
* var HEADER 40 40 req.http.Cookie
* var HEADER 40 40 req.http.host
* var BOOL 0 99 req.is_hitmiss
* var BOOL 0 99 req.is_hitpass
* var STRING 0 99 req.method
* var STRING 0 40 req.proto
* var STRING 41 99 req.proto
* var INT 0 99 req.restarts
* var STEVEDORE 0 99 req.storage
* var DURATION 0 99 req.ttl
* var STRING 0 99 req.url
* var STRING 0 99 req.xid
* none VOID 0 99 req_top
* none HEADER 0 99 req_top.http*
* var STRING 0 99 req_top.method
* var STRING 0 99 req_top.proto
* var STRING 0 99 req_top.url
* var HTTP 0 99 resp
* var BODY 0 99 resp.body
* var BOOL 41 99 resp.do_esi
* var STRING 0 99 resp.filters
* none HEADER 0 99 resp.http*
* var HEADER 40 40 resp.http.Content-Type
* var HEADER 40 40 resp.http.Retry-After
* var BOOL 0 99 resp.is_streaming
* var STRING 0 40 resp.proto
* var STRING 41 99 resp.proto
* var STRING 0 99 resp.reason
* var INT 0 99 resp.status
* action VOID 40 41 return
* none VOID 0 99 server
* var STRING 0 99 server.hostname
* var STRING 0 99 server.identity
* var IP 0 99 server.ip
* none VOID 41 99 sess
* var STRING 41 99 sess.xid
* action VOID 40 41 set
* none VOID 40 41 storage
* var STEVEDORE 40 41 storage.s0
* var BYTES 40 41 storage.s0.free_space
* var BOOL 40 41 storage.s0.happy
* var BYTES 40 41 storage.s0.used_space
* var STEVEDORE 40 41 storage.Transient
* var BYTES 40 41 storage.Transient.free_space
* var BOOL 40 41 storage.Transient.happy
* var BYTES 40 41 storage.Transient.used_space
* none VOID 41 41 sub
* action VOID 40 41 synthetic
* func BOOL 40 41 true
* action VOID 40 41 unset
* none VOID 41 41 vcl
* sub VOID 40 41 vcl_backend_error
* sub VOID 40 41 vcl_backend_fetch
* sub VOID 40 41 vcl_backend_response
* sub VOID 40 41 vcl_deliver
* sub VOID 40 41 vcl_fini
* sub VOID 40 41 vcl_hash
* sub VOID 40 41 vcl_hit
* sub VOID 40 41 vcl_init
* sub VOID 40 41 vcl_miss
* sub VOID 40 41 vcl_pass
* sub VOID 40 41 vcl_pipe
* sub VOID 40 41 vcl_purge
* sub VOID 40 41 vcl_recv
* sub VOID 40 41 vcl_synth
*/
However if I make a error in my VCL file, like replace .host with host, I get a VCC compiler error:
Message from VCC-compiler:
Expected '.' got 'host'
(program line 93), at
('/etc/varnish/default.vcl' Line 17 Pos 5)
host = "127.0.0.1";
----####---------------
In backend specification starting at:
('/etc/varnish/default.vcl' Line 16 Pos 1)
backend default {
#######----------
Running VCC-compiler failed, exited with 2
VCL compilation failed
Any ideas what am I doing wrong?
You're not doing anything wrong.
This is what the -C option does according to the docs:
Output VCL code compiled to C language
What you're seeing is the C representation of the VCL file. The VCC thread of the varnishd process will transpile the VLC code into C code. This C code will be compiled into machine code and the .so file that results from the compilation will be linked to the varnishd runtime process prior to execution.
As long as you're not making any syntax errors, the -C option will spit out the C code. Once you make a mistake in the VCL, the compilation will fail and you'll get an error.
VCL validation with varnishadm
There are other ways to validate your VCL file.
You can either add your VCL code as an inline string to varnishadm vcl.inline. See https://varnish-cache.org/docs/6.0/reference/varnish-cli.html#vcl-inline-configname-quoted-vclstring-auto-cold-warm for documentation.
You can also use the following commands to load, validate & discard the VCL file:
sudo varnishadm vcl.load validation default.vcl
sudo varnishadm vcl.discard validation
The first command will load the default.vcl file and try to compile it. When it success the validation configuration is stored and can be used in production through varnishadm vcl.use validation.
But we're not going to do that. Because this is only a validation run, we'll remove the validation config through varnishadm vcl.discard validation as seen in the example above.
The string will only contain 0's or 4's. The string will start with 4. example: 444, 44, 40, 4400, 4440, etc. These all are valid strings but 404 is not valid.
Currently, I am checking if 4 is present immediately after 0. I am not sure that this one is efficient one.
If you mean leading 4 and following 0.
use regexp
package main
import (
"regexp"
)
func check(s string) bool {
return regexp.MustCompile(`^4+0*$`).MatchString(s)
}
func main() {
for _, tt := range []string{"444", "44", "40", "4400", "4440"} {
if !check(tt) {
panic("want true: " + tt)
}
}
for _, tt := range []string{"404", "040"} {
if check(tt) {
panic("want false: " + tt)
}
}
}
non-regexp
package main
func check(s string) bool {
i := 0
r := []rune(s)
for i = 0; i < len(r); i++ {
if r[i] != '4' {
break
}
}
if i == 0 {
return false
}
for ; i < len(r); i++ {
if r[i] != '0' {
return false
}
}
return true
}
func main() {
for _, tt := range []string{"444", "44", "40", "4400", "4440"} {
if !check(tt) {
panic("want true: " + tt)
}
}
for _, tt := range []string{"404", "040"} {
if check(tt) {
panic("want false: " + tt)
}
}
}
faster version
func check(s string) bool {
i, l := 0, len(s)
for ; i < l; i++ {
if s[i] != '4' {
break
}
}
if i == 0 {
return false
}
for ; i < l; i++ {
if s[i] != '0' {
return false
}
}
return true
}
For example,
package main
import "fmt"
func isFourZero(s string) bool {
i := 0
var four bool
for ; i < len(s) && s[i] == '4'; i++ {
four = true
}
if four {
if i >= len(s) {
return true
}
var zero bool
for ; i < len(s) && s[i] == '0'; i++ {
zero = true
}
if zero {
if i >= len(s) {
return true
}
}
}
return false
}
func main() {
tests := []struct{ s string }{
{"444"}, {"44"}, {"40"}, {"4400"}, {"4440"}, {"404"}, {"004"},
}
for _, test := range tests {
fmt.Printf("%q \t %t\n", test.s, isFourZero(test.s))
}
}
Output:
"444" true
"44" true
"40" true
"4400" true
"4440" true
"404" false
"004" false
Since we care about speed, let's look at some benchmarks:
BenchmarkIsFourZeroPeterSO-4 10000000 201 ns/op
BenchmarkValidateYogeshDesai-4 5000000 347 ns/op
BenchmarkCheckMattn-4 2000000 602 ns/op
fourzero_test.go:
package main
import (
"strings"
"testing"
)
var tests = []struct{ s string }{
{"444"}, {"44"}, {"40"}, {"4400"}, {"4440"}, {"404"}, {"004"},
}
func BenchmarkIsFourZeroPeterSO(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, test := range tests {
isFourZero(test.s)
}
}
}
func BenchmarkValidateYogeshDesai(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, test := range tests {
validate(test.s)
}
}
}
func BenchmarkCheckMattn(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, test := range tests {
check(test.s)
}
}
}
func isFourZero(s string) bool {
i := 0
var four bool
for ; i < len(s) && s[i] == '4'; i++ {
four = true
}
if four {
if i >= len(s) {
return true
}
var zero bool
for ; i < len(s) && s[i] == '0'; i++ {
zero = true
}
if zero {
if i >= len(s) {
return true
}
}
}
return false
}
func validate(str string) bool {
if strings.HasPrefix(str, "4") {
for i := 0; i < len(str)-1; i++ {
if (str[i] == '0') && (str[i+1] == '4') {
return false
}
}
} else {
return false
}
return true
}
func check(s string) bool {
i := 0
r := []rune(s)
for i = 0; i < len(r); i++ {
if r[i] != '4' {
break
}
}
if i == 0 {
return false
}
for ; i < len(r); i++ {
if r[i] != '0' {
return false
}
}
return true
}
No RegExp
package main
import (
"fmt"
"strings"
)
func validate(str string) bool {
if strings.HasPrefix(str, "4") {
for i:= 0; i < len(str)-1; i++ {
if (str[i] == '0') && (str[i+1] == '4') {
return false
}
}
}else { return false }
return true
}
func main() {
data := []string{"4", "44", "4400", "4440", "404", "004"}
for _, val := range data {
fmt.Println(validate(val))
}
}
Output:
true
true
true
false
false
The following is another implementation using only a single loop:
func yetAnotherValidation(s string) bool {
//INVALID: if empty OR not started with '4'
if len(s) == 0 || s[0] != '4' {
return false
}
//INVALID: if len(s) > 2 AND contains "404"
for k := 2; k < len(s); k++ {
if s[k] == '4' && s[k-1] == '0' && s[k-2] == '4' {
return false
}
}
return true
}
Note:
*404* (e.g. 404, 4404, 4040, ...) is INVALID.
If s contains a character other than 0 or 4, the result will be undefined (depending on the position of that character). If you need to ensure whether the input only contains 0 or 4, then:
func yetAnotherValidation2(s string) bool {
//INVALID: if empty OR not started with '4'
if len(s) == 0 || s[0] != '4' {
return false
}
//INVALID: if second digit is not 0 or 4
if len(s) > 1 && s[1] != '0' && s[1] != '4' {
return false
}
//For len(s) > 2
for k := 2; k < len(s); k++ {
if s[k] == '4' && s[k-1] == '0' && s[k-2] == '4' {
return false
} else if s[k] != '0' && s[k] != '4' {
//Neither 0 nor 4
return false
}
}
return true
}
UPDATE:
Test and benchmark result:
=== RUN TestValidate
444 true
44 true
40 true
4400 true
4440 true
404 false
004 false
--- PASS: TestValidate (0.00s)
BenchmarkYetAnotherValidation-4 50000000 38.5 ns/op
BenchmarkYetAnotherValidation2-4 30000000 45.6 ns/op
BenchmarkIsFourZero-4 20000000 54.5 ns/op
BenchmarkCheckMattn-4 10000000 144 ns/op
BenchmarkCheckMattnFast-4 30000000 50.2 ns/op
Having issues trying to decipher the principal variation (PV) results.
"The principal variation is a path from the root to a leaf node, in which every node has the same value. This leaf node, whose value determines the minimax value of the root, is called the principal leaf."
The game demo below PV (move,eval) shows this line:
4,0 7,0 6,0 5,0 2,1
How can this be a valid PV since not ALL eval nodes have the same value? The AI never loses, but since the dizzying PV seems bogus, it casts a dark shadow on the AI logic. :( Hopefully, it's just a PV bug!
| | 0 | 1 | 2
---|---|--- ---|---|---
| | 3 | 4 | 5
---|---|--- ---|---|---
| | 6 | 7 | 8
Your move: 8
Thinking Cycles....: 2784300
Boards Generated...: 3956
Principal Variation: 4,0 7,0 6,0 5,0 2,1
Alpha-Beta Cutoffs.: 931
Computer Evaluation: 0
Computer Move......: 4
| | 0 | 1 | 2
---|---|--- ---|---|---
| X | 3 | 4 | 5
---|---|--- ---|---|---
| | O 6 | 7 | 8
Your move: 7
Thinking Cycles....: 410484
Boards Generated...: 575
Principal Variation: 6,0 5,0 2,1
Alpha-Beta Cutoffs.: 63
Computer Evaluation: 0
Computer Move......: 6
| | 0 | 1 | 2
---|---|--- ---|---|---
| X | 3 | 4 | 5
---|---|--- ---|---|---
X | O | O 6 | 7 | 8
Your move: 2
Thinking Cycles....: 42808
Boards Generated...: 45
Principal Variation: 5,0 3,0 1,0 0,0
Alpha-Beta Cutoffs.: 1
Computer Evaluation: 0
Computer Move......: 5
| | O 0 | 1 | 2
---|---|--- ---|---|---
| X | X 3 | 4 | 5
---|---|--- ---|---|---
X | O | O 6 | 7 | 8
Your move: 3
Thinking Cycles....: 6892
Boards Generated...: 4
Principal Variation: 0,0 1,0
Alpha-Beta Cutoffs.: 0
Computer Evaluation: 0
Computer Move......: 0
X | | O 0 | 1 | 2
---|---|--- ---|---|---
O | X | X 3 | 4 | 5
---|---|--- ---|---|---
X | O | O 6 | 7 | 8
Your move: 1
X | O | O 0 | 1 | 2
---|---|--- ---|---|---
O | X | X 3 | 4 | 5
---|---|--- ---|---|---
X | O | O 6 | 7 | 8
A draw! (*_*)
If anyone sees a bug in my code, please let me know. Thanks.
// Tic-Tac-Toe - Iterative implementation of alpha beta tree search.
// Built with Microsoft Visual Studio Professional 2013.
#include "stdafx.h"
#include <windows.h>
#include <intrin.h>
#include <stdint.h>
#define INFINITY 9999
#define NO_MOVE 9
#define NO_EVAL 2
#define X 1
#define O -1
#define Empty 0
struct values
{
int nodeMove;
int nodeEval;
int alpha;
int beta;
int player;
int board[9];
};
struct line
{
int nodeMove;
int nodeEval;
};
struct values moves[9];
int bestMove, bestEval;
int nodesCreated;
int abCutoffs;
int pvDepth, pvBestDepth;
// The principal variation pv[9] is a path from the root to a leaf node, in which every node
// has the same value. This leaf node, whose value determines the minimax value of the root,
// is called the principal leaf.
struct line pv[9] = {
{ NO_MOVE, NO_EVAL }, { NO_MOVE, NO_EVAL }, { NO_MOVE, NO_EVAL },
{ NO_MOVE, NO_EVAL }, { NO_MOVE, NO_EVAL }, { NO_MOVE, NO_EVAL },
{ NO_MOVE, NO_EVAL }, { NO_MOVE, NO_EVAL }, { NO_MOVE, NO_EVAL }
};
struct line bestPV[9] = {
{ NO_MOVE, NO_EVAL }, { NO_MOVE, NO_EVAL }, { NO_MOVE, NO_EVAL },
{ NO_MOVE, NO_EVAL }, { NO_MOVE, NO_EVAL }, { NO_MOVE, NO_EVAL },
{ NO_MOVE, NO_EVAL }, { NO_MOVE, NO_EVAL }, { NO_MOVE, NO_EVAL }
};
int board_eval(int *b)
{
// Rows.
if (b[0] && b[0] == b[1] && b[1] == b[2]) return b[0];
if (b[3] && b[3] == b[4] && b[4] == b[5]) return b[3];
if (b[6] && b[6] == b[7] && b[7] == b[8]) return b[6];
// Cols.
if (b[0] && b[0] == b[3] && b[3] == b[6]) return b[0];
if (b[1] && b[1] == b[4] && b[4] == b[7]) return b[1];
if (b[2] && b[2] == b[5] && b[5] == b[8]) return b[2];
// Center is empty.
if (!b[4]) return 0;
// Diags.
if (b[0] == b[4] && b[4] == b[8]) return b[0];
if (b[2] == b[4] && b[4] == b[6]) return b[2];
return 0;
}
void displayboard(int depth)
{
const char *t = "O X";
printf("\n\t %c | %c | %c\t\t 0 | 1 | 2\n", t[moves[depth].board[0] + 1], t[moves[depth].board[1] + 1], t[moves[depth].board[2] + 1]);
printf("\t---|---|---\t\t---|---|---\n");
printf("\t %c | %c | %c\t\t 3 | 4 | 5\n", t[moves[depth].board[3] + 1], t[moves[depth].board[4] + 1], t[moves[depth].board[5] + 1]);
printf("\t---|---|---\t\t---|---|---\n");
printf("\t %c | %c | %c\t\t 6 | 7 | 8\n\n", t[moves[depth].board[6] + 1], t[moves[depth].board[7] + 1], t[moves[depth].board[8] + 1]);
}
int find_move(int *board_arr, int nodeMove)
{
int i;
// Speedup loop using nodeMove instead of 0.
for (i = nodeMove; i < 9; i++) {
if (board_arr[i] == Empty)
return i;
}
return NO_MOVE;
}
int move_up_tree(int depth)
{
depth--;
if (depth == 0 && (moves[depth + 1].nodeEval > moves[depth].nodeEval))
{
bestMove = moves[depth].nodeMove;
bestEval = moves[depth + 1].nodeEval;
pvBestDepth = pvDepth;
pv[depth] = { bestMove, bestEval };
for (int i = 0; i < pvDepth; ++i)
{
bestPV[i].nodeMove = pv[i].nodeMove;
bestPV[i].nodeEval = pv[i].nodeEval;
pv[i] = { NO_MOVE, NO_EVAL };
}
}
if (moves[depth].player == X)
{
moves[depth].nodeEval = max(moves[depth].nodeEval, moves[depth + 1].nodeEval);
moves[depth].alpha = max(moves[depth].alpha, moves[depth].nodeEval);
}
else
{
moves[depth].nodeEval = min(moves[depth].nodeEval, moves[depth + 1].nodeEval);
moves[depth].beta = min(moves[depth].beta, moves[depth].nodeEval);
}
pv[depth] = { moves[depth].nodeMove, moves[depth].nodeEval };
moves[depth].nodeMove++;
moves[depth].nodeMove = find_move(moves[depth].board, moves[depth].nodeMove);
return depth;
}
int move_down_tree(int depth)
{
int eval;
depth++;
moves[depth] = moves[depth - 1];
nodesCreated++;
if (moves[depth].player == X)
{
moves[depth].board[moves[depth].nodeMove] = X;
moves[depth].player = O;
moves[depth].nodeEval = INFINITY;
}
else
{
moves[depth].board[moves[depth].nodeMove] = O;
moves[depth].player = X;
moves[depth].nodeEval = -INFINITY;
}
eval = board_eval(moves[depth].board);
// Leaf node.
if (eval || find_move(moves[depth].board, 0) == NO_MOVE)
{
moves[depth].nodeEval = eval;
moves[depth].nodeMove = NO_MOVE;
pvDepth = depth;
}
else
{
moves[depth].nodeMove = find_move(moves[depth].board, 0);
}
return depth;
}
void computer_move()
{
int depth = 0;
uint64_t c1, c2;
nodesCreated = 0;
abCutoffs = 0;
bestMove = NO_MOVE;
bestEval = -INFINITY;
moves[0].nodeMove = find_move(moves[0].board, 0);
moves[0].nodeEval = -INFINITY;
moves[0].alpha = -INFINITY;
moves[0].beta = INFINITY;
moves[0].player = X;
if (moves[0].nodeMove != NO_MOVE)
{
c1 = __rdtsc();
while (TRUE)
{
if (moves[depth].nodeMove == NO_MOVE)
{
if (depth == 0) break;
depth = move_up_tree(depth);
}
else if (moves[depth].alpha >= moves[depth].beta)
{
abCutoffs++;
moves[depth].nodeMove = NO_MOVE;
}
else
{
depth = move_down_tree(depth);
}
}
c2 = __rdtsc();
moves[0].board[bestMove] = X;
printf("\n");
printf("Thinking Cycles....: %d\n", c2 - c1);
printf("Boards Generated...: %d\n", nodesCreated);
printf("Principal Variation: ");
for (int i = 0; i < pvBestDepth; ++i) printf("%d,%d ", bestPV[i].nodeMove,bestPV[i].nodeEval);
printf("\n");
printf("Alpha-Beta Cutoffs.: %d\n", abCutoffs);
printf("Computer Evaluation: %d\n", bestEval);
printf("Computer Move......: %d\n", bestMove);
}
}
void init_board()
{
moves[0].board[0] = Empty;
moves[0].board[1] = Empty;
moves[0].board[2] = Empty;
moves[0].board[3] = Empty;
moves[0].board[4] = Empty;
moves[0].board[5] = Empty;
moves[0].board[6] = Empty;
moves[0].board[7] = Empty;
moves[0].board[8] = Empty;
}
void human_move()
{
int move;
char *p, s[100];
printf("Your move: ");
while (fgets(s, sizeof(s), stdin)) {
move = strtol(s, &p, 10);
if (p == s || *p != '\n') {
printf("Your move: ");
}
else break;
}
moves[0].board[move] = O;
}
int main(int argc, char **argv)
{
init_board();
displayboard(0);
while (1)
{
human_move();
computer_move();
displayboard(0);
if (board_eval(moves[0].board))
{
printf("Computer Wins! (-_-)\n");
init_board();
displayboard(0);
}
else if (find_move(moves[0].board, 0) == NO_MOVE)
{
printf("A draw! (*_*)\n");
init_board();
displayboard(0);
}
}
return 0;
}