Posted at

VarnishでVCLファイルを変換したCのソースを見てみる

More than 3 years have passed since last update.


VCLファイルをCに手動で変換する

varnishd — Varnish version 4.1.0 documentation-C オプションの説明に書かれているようにVCLファイルはCに変換してコンパイルされます。

運用時はVarnish起動時に自動的にVCLファイルをCに変換・コンパイルして読み込んでくれるので特に気にする必要はないです。

変換結果のCのソースファイルを見たい場合は以下のように手動でコンパイルします。

sudo varnishd -C -f ${VCLファイル名} > ${Cファイル名} 2>&1


例1: リクエストされたホスト名に応じてバックエンドを切り替えるVCL

Backends and virtual hosts in Varnishで紹介されています。

varnish-compiled-vcl-examples/virtualhost_backend.vcl at 9e0320d

sub vcl_recv {

if (req.http.host ~ "foo.com") {
set req.backend_hint = foo;
} elsif (req.http.host ~ "bar.com") {
set req.backend_hint = bar;
}
}

Cに変換した結果はvarnish-compiled-vcl-examples/virtualhost_backend.c at 9e0320dです。

int __match_proto__(vcl_func_f)

VGC_function_vcl_recv(VRT_CTX)
{
/* ... from ('input' Line 13 Pos 5) */
{
{
VRT_count(ctx, 1);
if (
VRT_re_match(ctx, VRT_GetHdr(ctx, &VGC_HDR_REQ_host), VGC_re_2)
)
{
VRT_count(ctx, 2);
VRT_l_req_backend_hint(ctx,
vgc_backend_foo
);
}
else if (
VRT_re_match(ctx, VRT_GetHdr(ctx, &VGC_HDR_REQ_host), VGC_re_3)
)
{
VRT_count(ctx, 3);
VRT_l_req_backend_hint(ctx,
vgc_backend_bar
);
}
...(snip)...

VCLファイル内で明示的にreturnしていない場合は、built-inのVCLの内容が自分のVCLの後に差し込まれます。

built-inの vcl_recv の内容は

varnish-compiled-vcl-examples/builtin.vcl at 643ddc5

# sub vcl_recv {

# if (req.method == "PRI") {
# /* We do not support SPDY or HTTP/2.0 */
# return (synth(405));
# }
# if (req.method != "GET" &&
# req.method != "HEAD" &&
# req.method != "PUT" &&
# req.method != "POST" &&
# req.method != "TRACE" &&
# req.method != "OPTIONS" &&
# req.method != "DELETE") {
# /* Non-RFC2616 or CONNECT which is weird. */
# return (pipe);
# }
#
# if (req.method != "GET" && req.method != "HEAD") {
# /* We only deal with GET and HEAD by default */
# return (pass);
# }
# if (req.http.Authorization || req.http.Cookie) {
# /* Not cacheable by default */
# return (pass);
# }
# return (hash);
# }

となっていて、Cへの変換結果はvarnish-compiled-vcl-examples/virtualhost_backend.c at 9e0320dとなっています。

  /* ... from ('Builtin' Line 47 Pos 5) */

{
{
VRT_count(ctx, 7);
if (
!VRT_strcmp(VRT_r_req_method(ctx), "PRI")
)
{
VRT_count(ctx, 8);
VRT_synth(ctx,
405
,
(const char*)0
);
VRT_handling(ctx, VCL_RET_SYNTH);
return (1);
}
VRT_count(ctx, 9);
if (
(
VRT_strcmp(VRT_r_req_method(ctx), "GET")&&
VRT_strcmp(VRT_r_req_method(ctx), "HEAD")&&
VRT_strcmp(VRT_r_req_method(ctx), "PUT")&&
VRT_strcmp(VRT_r_req_method(ctx), "POST")&&
VRT_strcmp(VRT_r_req_method(ctx), "TRACE")&&
VRT_strcmp(VRT_r_req_method(ctx), "OPTIONS")&&
VRT_strcmp(VRT_r_req_method(ctx), "DELETE"))
)
{
VRT_count(ctx, 10);
VRT_handling(ctx, VCL_RET_PIPE);
return (1);
}
VRT_count(ctx, 11);
if (
(
VRT_strcmp(VRT_r_req_method(ctx), "GET")&&
VRT_strcmp(VRT_r_req_method(ctx), "HEAD"))
)
{
VRT_count(ctx, 12);
VRT_handling(ctx, VCL_RET_PASS);
return (1);
}
VRT_count(ctx, 13);
if (
(
(VRT_GetHdr(ctx, &VGC_HDR_REQ_Authorization) != 0)||
(VRT_GetHdr(ctx, &VGC_HDR_REQ_Cookie) != 0))
)
{
VRT_count(ctx, 14);
VRT_handling(ctx, VCL_RET_PASS);
return (1);
}
VRT_count(ctx, 15);
VRT_handling(ctx, VCL_RET_HASH);
return (1);
}
}
}

VCLでの return はCでは VRT_handling 関数呼び出しに変換されることがわかります。


例2: リクエストされたホスト名に応じてストレージを切り替えるVCL

Partitioning your Varnish Cacheで紹介されています。

varnish-compiled-vcl-examples/partition_storage.vcl at 643ddc5

sub vcl_backend_response {

if (bereq.http.host ~ "foo") {
set beresp.storage_hint = "foo";
set beresp.http.x-storage = "foo";
} else if (bereq.http.host ~ "bar") {
set beresp.storage_hint = "bar";
set beresp.http.x-storage = "bar";
} else {
set beresp.storage_hint = "default";
set beresp.http.x-storage = "default";
}
}

Cに変換した結果はvarnish-compiled-vcl-examples/partition_storage.c at 643ddc5です。

int __match_proto__(vcl_func_f)

VGC_function_vcl_backend_response(VRT_CTX)
{
/* ... from ('input' Line 12 Pos 5) */
{
{
VRT_count(ctx, 2);
if (
VRT_re_match(ctx, VRT_GetHdr(ctx, &VGC_HDR_BEREQ_host), VGC_re_1)
)
{
VRT_count(ctx, 3);
VRT_l_beresp_storage_hint(ctx,
"foo",
vrt_magic_string_end
);
VRT_SetHdr(ctx, &VGC_HDR_BERESP_x_2d_storage,
"foo",
vrt_magic_string_end
);
}
else if (
VRT_re_match(ctx, VRT_GetHdr(ctx, &VGC_HDR_BEREQ_host), VGC_re_2)
)
{
VRT_count(ctx, 4);
VRT_l_beresp_storage_hint(ctx,
"bar",
vrt_magic_string_end
);
VRT_SetHdr(ctx, &VGC_HDR_BERESP_x_2d_storage,
"bar",
vrt_magic_string_end
);
}
else
{
VRT_count(ctx, 5);
VRT_l_beresp_storage_hint(ctx,
"default",
vrt_magic_string_end
);
VRT_SetHdr(ctx, &VGC_HDR_BERESP_x_2d_storage,
"default",
vrt_magic_string_end
);
}
}
}
...(snip)...

こちらも vcl_backend_response 内に return を書いていないので、この後にbuilt-inの vcl_backend_response の内容が差し込まれます。

varnish-compiled-vcl-examples/builtin.vcl at 643ddc5

# sub vcl_backend_response {

# if (beresp.ttl <= 0s ||
# beresp.http.Set-Cookie ||
# beresp.http.Surrogate-control ~ "no-store" ||
# (!beresp.http.Surrogate-Control &&
# beresp.http.Cache-Control ~ "no-cache|no-store|private") ||
# beresp.http.Vary == "*") {
# /*
# * Mark as "Hit-For-Pass" for the next 2 minutes
# */
# set beresp.ttl = 120s;
# set beresp.uncacheable = true;
# }
# return (deliver);
# }

Cへの変換結果はvarnish-compiled-vcl-examples/partition_storage.c at 643ddc5です。

  /* ... from ('Builtin' Line 154 Pos 5) */

{
{
VRT_count(ctx, 31);
if (
(
(VRT_r_beresp_ttl(ctx) <= 0)||
(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_3)||
((
!((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_4)))||
!VRT_strcmp(VRT_GetHdr(ctx, &VGC_HDR_BERESP_Vary), "*"))
)
{
VRT_count(ctx, 32);
VRT_l_beresp_ttl(ctx,
120
);
VRT_l_beresp_uncacheable(ctx,
(0==0)
);
}
VRT_count(ctx, 33);
VRT_handling(ctx, VCL_RET_DELIVER);
return (1);
}
}
}