ICAP(Internet Content Adaptation Protocol)メモ (ちょい訳?)

目的は、今までProxy等に直接実装されていたHTTPメッセージ書き換え機能の外部化。

セマンティクス

ICAPサーバは、Proxyの裏でメッセージ書き換え機能を担当する。RFC3507は"ICAP/1.0"。今のところこのバージョンしかない。
ICAPサーバと繋がっているHTTP Proxyを"HTTP surrogate"と呼ぶ。基本的に、HTTP surrogateがHTTPメッセージを横取りして、ICAPサーバに送りつけて変換させ、返ってきた結果を使う。コンテンツフィルタリングや、ウィルスチェックや、コンテンツ変換や、画像圧縮や、翻訳等に使える。

ICAPサーバが提供するメソッドはREQMOD(HTTPリクエストの書き換え), RESPMOD(HTTPレスポンスの書き換え), OPTIONSの3種類である。これらはクライアントが呼び分ける。最初にOPTIONSメソッドを呼んで、該当ICAPサーバが提供する機能を確認する。
REQMODでは、HTTP surrogateは受け取ったユーザのHTTPリクエストを、すぐにICAPサーバに送りつけて書き換える。
RESPMODでは、HTTP surrogateはいったんユーザのHTTPリクエストをHTTPサーバへ送り、その結果をICAPサーバに送って書き換える。
ICAPサーバは、リクエスト書き換え要求に対し、リクエストを書き換える代わりに、いきなりレスポンスを送りつけても良い。フィルタリング等で有効。

ICAPは、TCP/IP上のrequest/responseプロトコルとして設計されている (4, 8.1)

  • HTTP上には乗っていない。マッチングさせるのが面倒らしい。
  • メッセージの形態はHTTPスタイル (4.1)
  • keep-aliveのためのルールはHTTP/1.1と同じ(4.1)
  • 書き換えたいHTTPメッセージがICAPメッセージに包含されているので(Encapsulated)、必要な書き換えを施して、もしくは必要なHTTP Responseを生成して、ICAP Response Messageとして戻す。

ICAP_URI (4.2)

icap://[userinfo@]host[:port]/absolute_path[?query]

ICAPヘッダ (4.3)

ユーザ定義ヘッダは"X-"で開始すること。フィールド名はcase-insensitive

Request/Responseで共通のヘッダ (4.3.1)

HTTPと共通なものは以下。

  • Cache-Control
  • Connection
  • Date
  • Expires
  • Pragma
  • Trailer
  • Upgrade

Transfer-Encodingは使えない。

ICAP specificなのは以下。

  • Encapsulated

Requestヘッダ (4.3.2)

ICAPのメソッドは次の三種類。ユーザ定義で増やしても良い。

  • REQMOD (Optional)
  • RESPMOD (Optional)
  • OPTIONS (MUST)

リクエストラインの例:

RESPMOD icap://icap.example.net/translate?mode=french ICAP/1.0

Request-specificヘッダのうち、HTTPから継承されたものは以下。

  • Authorization
  • Allow
  • From
  • Host
  • Referer
  • User-Agent

ICAP specificなものは以下。

Responseヘッダ (4.3.3)

ステータスラインの例:

ICAP/1.0 200 OK

ステータスコードは基本的にHTTPに従う。HTTPと意味が異なるのは以下の2種である。

  • 100 - Continue after ICAP Preview.
  • 204 - No modifications needed.

その他のエラーコード:

  • 400 - Bad request.
  • 404 - ICAP Service not found.
  • 405 - Method not allowed for service. (REQMODしか対応していないサービスにRESPMODを送った)
  • 408 - Request timeout.
  • 500 - Server error.
  • 501 - Method not implemented.
  • 502 - Bad Gateway. ICAP proxyとして動いていて、さらに裏にあるサーバがerrorを返した。
  • 503 - Service overloaded.
  • 505 - ICAP version not supported by server.

HTTPと共通のResponse specificヘッダは以下。

  • Server

ICAP-specificなのは以下。

  • ISTag

HTTPメッセージのencapsulation (4.4, 4.4.1, 4.4.2)

この辺りからオリジナリティ。同時にメモモードに移行。

ICAPメッセージはHTTP requestもしくはHTTP request/responseのメッセージを包含している(カプセル化)。カプセル化されたHTTPメッセージを"encapsulated"、それを包み込んでいるICAPメッセージ部分を"encapsulating"と呼ぶ。
なお、ICAPではデフォルトでHTTPの"chunked" transfer-codingを用いる。メッセージのプレビューを実現するためである。ただし、"Transfer-Encoding"ヘッダは存在しないことに注意。

まず、すべてのICAPメッセージはEncapsulatedヘッダを持たなければならない(MUST)。

Encapsulated: req-hdr=0, res-hdr=45, res-body=100

req-hdrとかは見ればわかる意味(encapsulated entity)。数字はICAPボディ開始点からのバイトオフセット(10進数)。

encapsulated entityには以下がある。

  • reqhdr
  • reshdr
  • reqbody
  • resbody
  • optbody

encapsulated entityの宣言順は、実際にそれがバイトストリーム上に現れる順番と一致しなければならない(MUST)。つまり、offsetの数字は単調増加で無ければならない(MUST)。

どのメソッドのRequest/Responseであるかにより、宣言可能なencapsulated entityが決まってくる。

  • REQMOD requestのとき: [req-hdr] req-body
  • REQMOD responseのとき: {[req-hdr] req-body} | {[res-hdr] res-body}
  • RESPMOD requestのとき: [req-hdr] [res-hdr] res-body
  • RESPMOD responseのとき: [res-hdr] res-body
  • OPTIONS responseのとき: opt-body

一つのICAPメッセージにbodyは一つのみ。bodyが存在しない場合は"null-body"を宣言する。例えば

Encapsulated: req-hdr=0, null-body=412

RESPMODメソッドではHTTP Requestのボディは取れないことに注意。

ICAPメッセージに含まれるHTTPメッセージは、通常のHTTPと同じく、リクエストライン/ステータスラインで始まり(MUST)、ヘッダが並び、空行が入り(MUST)、必要があればボディが続く形態をとる。従って、空行でもreq-hdrとreq-body等を分離することは可能になる。

  • ICAPメッセージは、End-to-End HTTPヘッダをencapsulateすべきである(SHOULD)。
  • ICAPメッセージは、Hop-by-Hop HTTPヘッダをencapsulateすべきでない(MUST NOT)。

ただし、"Proxy-Authenticate"ヘッダと"Proxy-Authorization"ヘッダは、Hop-by-Hopではあるが、ICAPヘッダを使って転送されなければならない(MUST)。Encapsulated body内ではないことに注意。

HTTP surrogateがproxyとして付加したEncapsulated messageに含まれる"Via"ヘッダは、ICAPサーバが書き換えるべきである(SHOUlD)。付加するViaヘッダはプロトコルとして"ICAP/1.0"を指定しなければならない(MUST)。
REQMODメソッドでResponseを直接返す場合などには不要。また、"ICAP/1.0"を指定しろと書いてある割に、その後のサンプルでは"1.0"としか書いていない。ただし、HTTP仕様的には"protocol-name '/' version"なので、やはり"ICAP/1.0"が望ましいだろう。

メッセージプレビュー (4.5)

ICAP clientは、ICAPリクエストをサーバに送る際、「プレビュー」を含めることができる。ICAPサーバはこれにより、書き換えが必要であるかどうかを早期に判断してopt-outすることが可能である。

OPTIONSメソッドにより、ICAPサーバは何byteが必要かを指定すべきである(SHOULD)。クライアントは少なくとも4096バイトのプレビューを提供する能力を持つべきである(SHOULD be able to)。クライアントは、プレビューを希望するICAPサーバに対しプレビューを提供すべきであり(SHOULD)、サーバが提示した希望サイズより大きなプレビューを渡すべきでない(SHOULD NOT)。

ICAPクライアントは、プレビューを行う際には、プレビューの長さを示す"Preview"ヘッダを含めなければならない(MUST)。Previewヘッダの示す値は0でも良い。

ICAPクライアントは、ICAPヘッダを送った後、Previewヘッダで示した分だけ(か、それより少ない)のボディを送り、そこで送信を中断して、ICAPサーバのレスポンスを待つ。プレビューとそれ以降のデータは別のchunkになるため、ICAPサーバはバイトストリームから明確にプレビューの終わりを知ることができる。chunkの終わりには、"0\r\n\r\n"ターミネータが付く(RFC中のメッセージサンプルは間違っている)。

HTTPの100 Continueに似ているが、HTTPの場合にはヘッダ送信終了時に待つのに対し、ICAPではボディを途中まで送ってから待つことができる。

プレビューに対するICAPサーバのレスポンスは、以下の3つの内どれかでなければならない(MUST)。

  • 204 No Content. ICAPサーバはリクエストに対して何もする気がない。
  • REQMOD / RESPMOD レスポンス。ICAPサーバは完全なレスポンスを直接返す。
  • 100 Continue. ICAPサーバはリクエストの残りが必要。ICAPクライアントは残りのデータをプレビューの次のchunkから送らなければならない(MUST)。メッセージの全てがプレビューchunkに入ってしまっている場合は、ICAPサーバは100 Continueを送ってはならない(MUST NOT)。

ICAPはHTTPサーバから何byte受け取れるか不明なので、プレビュー内では、実際のメッセージの終わりを示す方法が必要である。このために、HTTP/1.1に基づいて、"ieof" chunk extensionを使う。ICAPクライアントは、プレビューの最後のchunkのターミネータとして、これを用いる。プレビュー以外では不要であることに注意。

\r\n
0; ieof\r\n\r\n

1024byteのPreviewを宣言した状態で、HTTPサーバが1024byteを2つのchunkに分けて送った場合、ICAPリクエストのencapsulated bodyは以下になる。

200\r\n
<512 bytes of data>\r\n
200\r\n
<512 bytes of data>\r\n
0; ieof\r\n\r\n

1024byteのPreviewを宣言した状態で、HTTPサーバが1025bytes送ってきた場合。この場合、プレビューは終了しているので、最後のchunkは単純に"0\r\n\r\n"でよい。

200\r\n
<512 bytes of data>\r\n
200\r\n
<512 bytes of data>\r\n
0\r\n\r\n

<サーバは100 Continueメッセージを応答>

1\r\n
<1 byte of data>\r\n
0\r\n\r\n

"204 No Content"

ICAPクライアントは、HTTPメッセージ全体を保存しておき、ICAPサーバの"No Content"に対応しても良い(MAY)。その場合、ICAPリクエストヘッダに"Allow: 204"を指定すること。

ICAPサーバは、"Allow: 204"を含まないリクエストを受け取った場合、204を返してはならない(MUST NOT)。ただし、プレビューはこの限りでない。

ISTag ("ICAP ServiceTag")

ICAPサーバは、全てのICAPレスポンスに対して"ISTag"ヘッダを含めなければならない(MUST)。ISTagは、そのICAP URIが示すサービスの同一性を示す一種の"cookie"である。ISTagは、null文字を含まない英数字で構成された32バイトまでの文字列である。例えばソフトウェア名とバージョンなどが考えられる。ISTagが変わらないうちは、前回の変更内容は今でも最新であると判断できる。

例えば、ウィルスチェックサービスであれば、データベースのupdateに伴いISTagを変更することで、HTTP surrogate中のキャッシュが無効であることを示すことができる。

OPTIONS

OPTIONSレスポンスが返せるヘッダは以下のとおり。

  • Methods (MUST) - MethodsにOPTIONSを含めてはならない(MUST NOT)
  • Service (Optional) - サービス名
  • ISTag (MUST)
  • Encapsulated (MUST)
  • Opt-body-type - opt-bodyが存在する場合は含めなければならない(MUST)。
  • Max-Conections (Opional)
  • Options-TTL (Optional)
  • Date (Optional) - RFC1123
  • Service-ID (Optional)
  • Allow (Optional) : このRFCでは"204"だけが定義されている。
  • Preview (Optional) : プレビュー時の送信バイト数。
  • Transfer-Preview(Optional) : プレビューを送るべきファイル種別のファイル拡張子(!!!)のリスト。
  • Transfer-Ignore (Optional) : ICAPサーバに送るべきでないファイル種別のファイル拡張子のリスト。
  • Transfer-Complete (Optional) : プレビューなしで全体を送るべきファイル種別のファイル拡張子のリスト。

Transfer-*ヘッダのどれか一つは"*"を含まなければならないことに注意。
もし、Transfer-*が一つも送られなかった場合、プレビューなしで全てのメッセージがICAPサーバに送られる。

実際のサンプル

難しくないので、RFCをそのまま見ること。

この辺も参考http://www.symantec.com/region/jp/techsupp/enterprise/savse/se43/savse43_dg.pdf