Fastly の設定に適用条件を設定する

Fastly には各種設定がありますが、各設定に対して条件を設定することができます。例えば、リクエストの URL に特定の文字列を含んでいる場合には、特定のオリジンサーバを利用するとか、レスポンスに特定のヘッダを含んでいる場合にはキャッシュ時間を短くするなどです。
ここでは、条件の設定とその適用方法を紹介します。

#条件の設定方法と適用のながれ
基本的には下記の流れで条件設定を適用します。
1. 設定を作成する
2. 1の設定に条件を適用する（既存の条件を流用できる場合には選択する）

ここでは2の条件設定について説明します。条件設定は具体的な設定を見た方がわかりやすいので、いくつか例を紹介しながら説明します。

#条件の設定例
##オリジンをドメインによって振り分ける
Fastly のサービスはひとつのサービスで複数のドメインを設定することができます。ドメインによって利用するオリジンを分けたいという場合についてご紹介します。
オリジンについてはすでに設定がされているはずです。`CONFIGURE` - `ORIGIN` を選択すると下記のような画面が表示されます。ここで、条件を適用したいオリジンサーバの `Attach a condition` を選択します。

![origin_condition_mask.png](https://qiita-image-store.s3.amazonaws.com/0/149542/69df1341-db32-302c-b9d3-70377f8cd01b.png)
下記の画面が開きます。
![origin_condition_add_mask.png](https://qiita-image-store.s3.amazonaws.com/0/149542/fc68901f-ad2c-983c-cb71-a0c62ce75d06.png)

すでに存在する条件を流用する場合には `Select a condition` から選択ができますが、ここでは新規に作成するので、`CREATE A NEW REQUEST CONDTION` を選択すると条件設定画面が開きます。

![origin_condition_mask-a.png](https://qiita-image-store.s3.amazonaws.com/0/149542/5e40ded5-0e9a-c1ce-c86c-fbb1c92d627c.png)


* Type: 設定箇所により決まります。この場合にはオリジンの選択に対する設定なので Request のみ設定できます。 
* Name: 設定を識別する名前を設定します。重複がなければ任意に設定可能です。
* Apply if...: 条件を記載します。ここでは `req.http.host == "www.a-example.com"` と記載しています。リクエストのホストヘッダが www.a-example.com のときにこの設定が適用されるという意味になります。
* Adjust priority: 実行される場所を決定します。数値が小さい順に実行されます。デフォルトが10となっており、この場合はそのままにします。

この設定を行ったときの実際のコードを見てみましょう。設定を Activate しなくてもコードの確認は可能です。OPTIONS から Show VCL を選択すると下記のようなコードが追加されているのが確認できます。これを Activate すれば設定完了です。

```
  # Request Condition: Use Origin A Prio: 10
  if( req.http.host == "www.a-example.com" ) {
        
    set req.backend = F_a-example.com;
    
  
      }
  #end condition
```


##200番台以外をロギングする
次にログに適用してみます。ログの容量の問題から正常なリクエストはログせずに、想定外のリクエストのみにログを記録したいということがあるかもしれません。その条件を設定してみます。
今回はログの設定なので、`CONFIGURE` - `LOGGING` を選択します。該当ログの `Attach a condition` を選択し、`CREATE A NEW REQUEST CONDTION` から条件設定を開くところまで同じです。
基本的に、ログはコンテンツが配信される際に出力されることから Type は Response となります。下記のように設定することで200番台以外をログ出力の条件にすることができます。

![log_condition_mask.png](https://qiita-image-store.s3.amazonaws.com/0/149542/7e8dbf88-5232-9ace-76dc-dd6ff80f64d2.png)

##特定の URL を pass 設定にする
この利用方法は最もポピュラーかもしれません。デフォルトではキャッシュするものの、特定のパスを含む URL はキャッシュしないというケースです。
この設定は `CONFIGURE` - `SETTINGS` - `Request settings` から行います。画面内に `Attach a condition` のリンクがあるので、ここでこれまでの設定と同様に条件の設定を行います。

![request_condition_arrow.png](https://qiita-image-store.s3.amazonaws.com/0/149542/7286e405-2135-097c-cc2e-8803998e8294.png)

作成したコードをみてみると、下記が記載されており、設定はできているようです。

```
  # Request Condition: url pass Prio: 10
  if( req.url ~ "^/pass/" ) {        
    
       if (!req.http.Fastly-FF) {
         if (req.http.X-Forwarded-For) {
           set req.http.Fastly-Temp-XFF = req.http.X-Forwarded-For ", " client.ip;
         } else {
           set req.http.Fastly-Temp-XFF = client.ip;
         }
       } else {
         set req.http.Fastly-Temp-XFF = req.http.X-Forwarded-For;
       }
   
        return(pass);  
  
      }
  #end condition
```

Activate をすれば正常に動作するはずですが、ここでは Priority について少し考えてみましょう。
仮にこのコードの上に下記があったとします。これは png 拡張子をもつファイルはキャッシュするというコードです。`return(lookup)` によって vcl_recv のその下のコードは実施されません。よって、`/pass/example.png` というファイルがあった場合には、png ファイルとうい条件が初めに適用されてキャッシュされることになります。
もし、このファイルは pass にしたい場合にはどうしたらよいでしょうか。条件を変更するなどいくつかやり方はありますが、Priority を変更することによっても実現できます。上述のように Priority は実行の順序を変更できます。例えば、この場合、Priority の値を `5` にすることにより、pass のコードは png のコードより先に実行されることとなり、`/pass/example.png` は `pass` が URL に含まれるという条件が先に適用され、passされます。

```
  # Request Condition: cache png Prio: 10
  if( req.url.ext == "png" ) {

       if (!req.http.Fastly-FF) {
         if (req.http.X-Forwarded-For) {
           set req.http.Fastly-Temp-XFF = req.http.X-Forwarded-For ", " client.ip;
         } else {
           set req.http.Fastly-Temp-XFF = client.ip;
         }
       } else {
         set req.http.Fastly-Temp-XFF = req.http.X-Forwarded-For;
       }
          
      return(lookup);    
  
      }
  #end condition
```

このように条件設定は基本的に GUI 上で実施することができます。ただし、競合する設定がある場合にはどちらを先に実施すべきかを考慮しながら、Priority の値で順序をコントロールすることにより、より柔軟な設定を実現することができます。

#条件に利用される条件文
英語ドキュメントですが [VCL regular expression cheat sheet](https://docs.fastly.com/guides/vcl/vcl-regular-expression-cheat-sheet) を参照してみてください。以下にいくつか例を記載します。

* **req.url.ext == "jpg"** : 拡張子が jpg の場合(1)（完全一致）
* **req.http.host ~ "^www"** : ホストヘッダ（ドメイン）が www で始まる。`^` は先頭の文字を表す。`~` は部分一致で www で始まればその後ろは任意。
* **req.url ~ "\\.jpg$"** : 拡張子が jpg の場合(2)。`.`は`\`でエスケープしておりピリオドを表す。`$`は最後の文字を示す
* **req.url ~ "\\.(png|jpg|css|js)$"** : 拡張子が png, jpg, css, js のいずれか。`|` で OR を表す。
* **req.url ~ "\\.php(\?.*)?$"** : php 拡張子でクエリストリングが後ろに続いても可。`\?` で `?`文字を表す。それ以外の`.`,`*`,`?`は正規表現の特殊文字。
* **req.url ~ "\\.[abc]server$"** : `abc` のうちの一文字+serverが拡張子。
* **req.http.cookie && req.http.User-Agent** : リクエストに cookie および User-Agent ヘッダがある場合。`&&` は条件文の AND。
* **beresp.status == 500 || beresp.status == 503** : レスポンスのステータスコードが500もしくは503の場合。`||` は条件文の OR。
* **!req.url** : req.url が存在しない場合。`!` は否定を表す。req.url は基本的に全てのリクエストで存在するため、この条件は常に False となる。