VarnishとCookieとlibvmod-cookieについてメモ

VarnishはCookieが設定されているとキャッシュしない

Varnish チュートリアルにある Cookie のセクションから

Varnish will, in the default configuration, not cache a object coming from the backend with a Set-Cookie header present. Also, if the client sends a Cookie header, Varnish will bypass the cache and go directly to the backend.
https://www.varnish-cache.org/docs/3.0/tutorial/cookies.html

この挙動を確認

確認方法

現在時刻を返すだけのページを用意し、キャッシュされているなら、同じ時刻を返すし、キャッシュされていなければ、リクエスト時点の現在時刻を返すはず。

クライアントがCookieを送信する場合

現在時刻を返すページ

<?php
echo date('Y/m/d H:i:s') . "\n";
?>

このページを /date.php と /cookie/date.php に用意

Cookieを送信

curl を使って GET で Cookie 送信

$ curl --cookie "foo=bar" http://localhost:8080/date.php

VCL

/cookie 以下にアクセスされた時は、クライアントが送信した Cookie を削除し、キャッシュされるようにする。

sub vcl_recv {
  if (!(req.url ~ "^/cookie/")) {
    unset req.http.Cookie;
  }
}

実験

$ curl --cookie "foo=bar" http://localhost:8080/cookie/date.php
2013/12/31 07:26:36
$ curl --cookie "foo=bar" http://localhost:8080/cookie/date.php
2013/12/31 07:26:39
$ curl --cookie "foo=bar" http://localhost:8080/date.php
2013/12/31 07:26:49
$ curl --cookie "foo=bar" http://localhost:8080/date.php
2013/12/31 07:26:49

/cookie 以下ではキャッシュされている。

クライアントがCookieを設定する場合

現在時刻を返し、クッキーを設定するページ

<?php
setcookie("foo", "bar");
echo date('Y/m/d H:i:s') . "\n";
?>

このページを /setcookie.php と /cookie/setcookie.php に用意

Cookieを送信

curl を使って GET リクエスト。Set-Cookie 確認のため、レスポンスヘッダーをダンプする。

$ curl -D - http://localhost:8080/setcookie.php

VCL

/cookie 以下にアクセスされた時はサーバが送信した Set-Cookie を残しキャッシュされず、それ以外の場合はサーバーが送信した Set-Cookie を削除し、キャッシュされるようにする。
Set Cookie しているページは Varnish には hit_for_pass としてマークされ、次回以降はオリジンサーバにアクセスする。

sub vcl_fetch {
  if (!(req.url ~ "^/cookie/")) {
    unset beresp.http.set-cookie;
  }
}

実験

$ curl -D - http://localhost:8080/cookie/setcookie.php
HTTP/1.1 200 OK
Server: nginx/1.1.19
Content-Type: text/html
X-Powered-By: PHP/5.3.10-1ubuntu3.9
Set-Cookie: foo=bar
Transfer-Encoding: chunked
Date: Tue, 31 Dec 2013 07:41:16 GMT
X-Varnish: 1563644852
Age: 0
Via: 1.1 varnish
Connection: keep-alive

2013/12/31 07:41:16
$ curl -D - http://localhost:8080/cookie/setcookie.php
HTTP/1.1 200 OK
Server: nginx/1.1.19
Content-Type: text/html
X-Powered-By: PHP/5.3.10-1ubuntu3.9
Set-Cookie: foo=bar
Content-Length: 20
Accept-Ranges: bytes
Date: Tue, 31 Dec 2013 07:41:17 GMT
X-Varnish: 1563644853
Age: 0
Via: 1.1 varnish
Connection: keep-alive

2013/12/31 07:41:17
$ curl -D - http://localhost:8080/setcookie.php
HTTP/1.1 200 OK
Server: nginx/1.1.19
Content-Type: text/html
X-Powered-By: PHP/5.3.10-1ubuntu3.9
Transfer-Encoding: chunked
Date: Tue, 31 Dec 2013 07:41:28 GMT
X-Varnish: 1563644854
Age: 0
Via: 1.1 varnish
Connection: keep-alive

2013/12/31 07:41:28
$ curl -D - http://localhost:8080/setcookie.php
HTTP/1.1 200 OK
Server: nginx/1.1.19
Content-Type: text/html
X-Powered-By: PHP/5.3.10-1ubuntu3.9
Transfer-Encoding: chunked
Date: Tue, 31 Dec 2013 07:41:28 GMT
X-Varnish: 1563644855 1563644854
Age: 1
Via: 1.1 varnish
Connection: keep-alive

2013/12/31 07:41:28

vmod_cookie を使ってみる

vcl の標準機能だけで Cookie を操作するには、Cookie の文字列に対して正規表現をゴリゴリ書く必要がある。
これでは面倒だしメンテもしづらいので、Varnish Software の中の人がクッキーを操作するユーティリティー関数群を vmod-cookie にまとめてくれている。

https://github.com/lkarsten/libvmod-cookie

Install libvmod-cookie

Ubuntu でのインストール方法は 作者がブログにまとめてくれている

http://lassekarstensen.wordpress.com/2013/07/29/building-a-varnish-vmod-on-debian/

libtool

configure か make のタイミングで “libtoolize not found” というようなエラーが起きたので $ sudo apt-get install libtool して libtoolize をインストールした。

バージョンの不一致

コンパイル時にはビルド済み Varnish が必要。
3.0.5 の varnish が動いているのに 3.0.4 のコードベースに対してビルドすると、varnish の起動時に行われる VMOD のコンパイルで次のようなエラーが発生した。

Message from VCC-compiler:
Could not load module cookie
 /usr/lib/varnish/vmods/libvmod_cookie.so
 ABI mismatch, expected <Varnish 3.0.5 1a89b1f>, got <Varnish 3.0.4 9f83e8f>
('input' Line 1 Pos 8)
import cookie;
-------######-

Running VCC-compiler failed, exit 1

VCL compilation failed

ということで、マイナーバージョンも含めてバージョンをあわせましょう。

vmod_cookie で Cookie 操作

vmod_cookie はクライアントが送信する Cookie を vcl_fetch でごにょごにょするのが一番の使いどころ。
VCL ファイルで import cookie;し、 cookie.使いたい関数 で Cookie を操作すればよい。

リファレンスは次の URL を参照
https://github.com/lkarsten/libvmod-cookie/blob/3.0/README.rst

実験

実験用VCL

  • URL に delete が含まれる場合は、Cookie からキー “1” を削除
  • URL に filter が含まれる場合は、Cookie からキー “1,2” 以外を削除
  • クライアントには削除後の Cookie を設定

するような VCL を用意

import std;
import cookie;

backend default {
    .host = "127.0.0.1";
    .port = "80";
}

sub vcl_recv {
  cookie.parse(req.http.Cookie);
  std.log(cookie.get_string());  // Cookie 文字列全体を出力
  if (req.url ~ "delete") {
    cookie.delete("1");          // Cookie からキー "1" を削除
  } else if (req.url ~ "filter") {
    cookie.filter_except("1,2"); // Cookie からキー "1,2" 以外を削除
  }
  std.log("1 value is: " + cookie.get("1")); // Cookie のキー "1" の値を取得
  std.log("2 value is: " + cookie.get("2"));
  std.log("3 value is: " + cookie.get("3"));
  std.log(cookie.get_string());
  set req.http.cookie = cookie.get_string(); // クライアントクッキーを再設定
}

クライアントクッキーをダンプするページ

vmod-cookie で Cookie がどのように変更されるのか確認する。

<?php
print_r($_COOKIE)
?>

このページを /delete.php と /filter.php に用意

実験

クライアントからは Cookie "1=one;2=two;3=three" を送信

cookie.delete の確認

URL に delete が含まれる場合は、Cookie からキー “1” を削除

$ curl --cookie "1=one;2=two;3=three" http://localhost:8080/delete.php
Array
(
    [2] => two
    [3] => three
)

“1=one” だけが削除されている。

cookie.filter_except の確認

URL に filter が含まれる場合は、Cookie からキー “1,2” 以外を削除

$ curl --cookie "1=one;2=two;3=three" http://localhost:8080/filter.php
Array
(
    [1] => one
    [2] => two
)

確かに “3=three” だけが削除されている。

VCL のログの確認

VCL 内では std.log でログ出力している。
以下のようにして出力を確認できる

$ sudo varnishlog -i VCL_LOG
    0 VCL_Log      - libvmod-cookie: parsed 3 cookies.
   14 BackendClose - default
   14 BackendOpen  b default 127.0.0.1 53935 127.0.0.1 80
   14 BackendReuse b default
   12 SessionOpen  c 127.0.0.1 43142 :8080
   12 VCL_Log      c 1=one; 2=two; 3=three;
   12 VCL_Log      c 1 value is: one
   12 VCL_Log      c 2 value is: two
   12 VCL_Log      c 3 value is:
   12 VCL_Log      c 1=one; 2=two;
   12 ReqEnd       c 1825349847 1388499399.437688828 1388499399.441040993 0.000321388 0.003163099 0.000189066

Leave a comment