Studying HTTP > RFC-Translations related HTTP

この文書は、 J. Mogul, B. Krishnamurthy, F. Douglis, A. Feldmann, Y. Goland, A. van Hoff, D. Hellerstein: Delta encoding in HTTP (RFC 3229), January 2002. を 橋本英彦 が日本語訳した物です。 この文書の取り扱いについては、[Studying HTTP] の RFC 日本語訳を利用するにあたってに従って下さい。


Network Working Group
Request for Comments: 3229
Category: Standards Track
              J. Mogul
            Compaq WRL
      B. Krishnamurthy
            F. Douglis
                  AT&T
           A. Feldmann
 Univ. of Saarbruecken
             Y. Goland
           A. van Hoff
               Marimba
        D. Hellerstein
              ERS/USDA
          January 2002

HTTP における差分エンコーディング

この文書の位置付け

この文書は、インターネットコミュニティにおけるインターネット標準化過程プロトコルを規定し、改良のために議論と提案を求めるものである。 このプロトコルの標準化状態と状況については、"Internet Official ProtocolStandards" (STD 1) の最新版を参照していただきたい。 この文書の配布に制限は無い。

著作権表示

Copyright © The Internet Society (2002). All Rights Reserved.

概要

この文書は、差分エンコーディング{delta encoding} が HTTP/1.1 と互換性を持つ拡張としてどのようにサポートされるかを記述する。

多くの HTTP (Hypertext Transport Protocol) リクエストは、クライアントが既にキャッシュエントリに保持しているようなリソースのわずかに修正されたインスタンスの取得のためのものである。 調査の結果、そのような更新は頻繁に行われており、またその修正部分のだいたいは実際のエンティティよりも非常に小さいものであった。 そのような場合、もし記述の変更部分の最低限を転送できるならば、HTTP はリソースの新しいインスタンス全体を転送するよりも、効率的にネットワーク帯域幅を使用できるだろう。 これを "差分エンコーディング" と呼ぶ。

目次

1 導入
1.1 関連する調査と提案
2 目標
3 専門用語
4 HTTP メッセージ生成シーケンス
4.1 差分と範囲指定の関係
5 基本メカニズム
5.1 背景: HTTP キャッシュ検証の概要
5.2 差分の転送を要求する事
5.3 差分のアルゴリズムとフォーマットの選択
5.4 差分エンコードされたレスポンスの識別
5.5 キャッシュの安全性を保証する事
5.6 差分エンコードされたレスポンスの転送
5.7 範囲指定と差分エンコーディングが連結したリクエストの例
6 エンコーディングのアルゴリズムとフォーマット
7 基点インスタンス{base instances} の管理
7.1 If-None-Match ヘッダ中の複数のエンティティタグ
7.2 クライアントのキャッシュを管理するためのヒント
8 差分と中間キャッシュ
9 データの完全性のダイジェスト
10 仕様
10.1 プロトコルパラメータの仕様
10.2 IANA について
10.3 差分エンコードされたレスポンスの基本要件
10.4 ステータスコードの仕様
10.4.1 226 IM Used
10.5 ヘッダの仕様
10.5.1 Delta-Base
10.5.2 IM
10.5.3 A-IM
10.6 226 レスポンスについてのキャッシングの規則
10.7 内容コーディングがある時の差分の規則
10.7.1 内容コーディングがある時の差分の生成の規則
10.7.2 内容コーディングがある時の差分の適用の規則
10.7.3 A-IM, IM, content-codings の使用例
10.8 新たな Cache-Control 指示子
10.8.1 retain 指示子
10.8.2 im 指示子
10.9 差分エンコーディングと合わせての圧縮の使用
10.10 差分エンコーディングと multipart/byteranges
11 プロトコルによる負荷の定量化
12 セキュリティについての考察
13 謝辞
14 知的所有権
15 参照文献
16 筆者のアドレス
17 著作権表示全文

1 導入

World Wide Web は分散システムであり、リソース取得の遅れを減らすためにキャッシュからしばしば利益を得る。 インターネットや他の広域ネットワークからの Web リソース (文書や画像、アイコン、アプレット等) の取得は、通常その遅れが人間の知覚のしきい値を超える程の十分な時を経る。 しばしば、その遅れは数秒程数えられる。 キャッシュはしばしばこの取得遅れを無くしたりあるいは著しく減らす事ができる。

多くの Web リソースは時と経ると変化するので、実際のキャッシュへのアプローチは、ユーザに古くなった情報を提示する事を避けるために、一貫したメカニズムを含んでいなければならない。 元々、Hypertext TransferProtocol (HTTP) にはキャッシュのためのサポートはほとんど提供されていなかったが、運用上の圧力のもと、キャッシュ一貫性の維持のための単純なメカニズムをサポートする事が急速に展開した。

HTTP/1.0 [2] では、サーバは "最終更新{last-modified}" タイムスタンプをレスポンスに与える事ができる。 クライアントがこのレスポンスをキャッシュエントリに保持し、後にこのレスポンスを再利用しようとする場合、タイムスタンプを値に持つ "If-modified-since" フィールドを含むリクエストメッセージを送信するかもしれない; これは条件付きリソース取得として知られている。 条件付きリクエストを受信した時、サーバは完全なレスポンスを返すか、あるいは、リソースが変更されていない場合は、クライアントのキャッシュエントリがまだ有効である事を示すような、省略した返答を送る事ができる。 HTTP/1.0 ではまた、"Expires" タイムスタンプを使って、サーバがそのレスポンスはその時間まで有効であるだろうという事を示すための方法を持つ; その場合、クライアントは条件付き取得を使用した最初の有効性検証を行う事なく、その時間までキャッシュされたレスポンスのコピーを使う事ができる。

HTTP/1.1 [10] は、キャッシュの統一性とパフォーマンスを改善するために多くの新しい特徴を加えた。 しかし、それは条件付き取得へのレスポンスのために妥協を許さない{all-or-none} モデルを保っている: すなわち、サーバはそのリソースの価値が全然変わっていない事を示すか、現在の値全体を送信しなければならない。

しかし、常識では、Web リソースが変わった時でさえ、新しいインスタンスはしばしば古いものと本質的には似ていると示唆する (そしてその形跡はこれを裏付ける)。 もし二つのインスタンス間での違い、あるいは "差分" が、新しいインスタンス全体の代わりにクライアントに送る事ができる場合、古いインスタンスのキャッシュのコピーを持つクライアントは、新バージョンを構築するために差分を適用する事ができる。 有限な帯域幅の世界では、レスポンスのサイズやその遅れを減らす事は重要であるだろう。

ある人は差分をクライアントやプロクシのキャッシュからできるだけ利益を捻り出す方法として考えるだろう。 これは、"キャッシュライン" として全レスポンスを扱うよりむしろ、差分を置換可能な単位として任意のキャッシュレスポンスの断片を扱い、変更されていない部分を転送する事を避ける事ができる。

この文書は、クライアントとサーバがオーバーヘッドを最小にするような差分エンコーディングを使用できるようにする、HTTP/1.1 の互換性をもつ拡張セットを提案する。

我々は、読者が HTTP/1.1 の仕様に精通している事を仮定する。

1.1 関連する調査と提案

接続や保存に関するコストを低減するための差分エンコーディングの考えは新しいものではない。 例えば、MPEG-1 ビデオ圧縮標準は時々 still-imageframes を送信するが、送られたほとんどの frame は (すごく単純化するために) 隣接する frame からの変更としてエンコードされる。 ソフトウェアバージョンコントロールのための SCCS と RCS [27] のシステムでは、差分として中間のバージョンを表わす; SCCS は元のバージョンで始まり前方の差分を加えた後のものをエンコードし、RCS はその成功版からの逆の差分として前のバージョンをエンコードする。 遅いリンク上での IP と TCP の各ヘッダを圧縮するための Jacobson の技術 [17] は、差分エンコーディングの巧妙で、高度に特定化された形式を使用する。

この歴史にもかかわらず、恐らく HTTP キャッシングについての開発が多少無計画なものだったので、誰かが HTTP に差分エンコーディングを適用する事を思いつくまでに数年も費やしたように思われる。 差分エンコーディングについて最初に発表された提案は、HTTP キャッシュ削除ポリシー [30] に関する論文中で Williams らによったように見えるが、これらの著者はその後までその設計について詳しく述べる事はしなかった [29]

WebExpress プロジェクト [15] は、(それが "differencing" と呼ばれるような) HTTP のための差分エンコーディングの実装についての最初に発表された記述であるように思われる。 WebExpress は特に無線の環境に向けられたもので、多くの直行する{orthogonal} 最適化を含んでいる。 また、WebExpress の設計は HTTP プロトコル自体の変更を提案するよりもむしろ、HTTP メッセージストリームを最適化された形式に変換するためにそのストリームの間に置かれたプロクシを使用するものとなっている。 WebExpress differencing のために報告された結果は印象的であるが、それはわずかに選択されたベンチマークに制限されている。

Banga ら [1] は、最適化された差分の使用について記述いたが、それは遅いリンクの両端の間に置かれたプロクシの層が待ち時間を減らすために協調するというものであった。 クライアント側のプロクシがリソースのキャッシュされたコピーを持っていた場合、サーバ側のプロクシは単に差分 (あるいは304 [Not Modified] レスポンス) を送る事ができる。 もしサーバ側のプロクシがキャッシュされたコピーを持っていたら、クライアント側のプロクシにその (恐らく古くなっている) コピーを、そして (もし必要ならば) 一旦サーバ側のプロクシがオリジンサーバへ自身のキャッシュエントリを検証した差分を楽観的に送る事ができる。 この楽観的な差分の使用は、差分エンコーディングとは異なり、オリジンサーバからの "Not Modified" レスポンスを見込む事による待ち時間の改善を試み、実際にはネットワーク上に送信されるバイト数を増加させる。 この楽観的な差分の報告書は、WebExpress の報告書のように、HTTP プロトコル自体の変更を提案するものではなく、小さな選択された URL のセットについてのみの結果を報告した。

Mogul ら [23] は、差分エンコードされたレスポンスによる潜在的な利益を計るために、二つの異なるサイトで、完全な HTTP メッセージ内容の長さを追跡した。 それらは、差分エンコーディングが HTTP 内容タイプの重要な部分集合についてレスポンスサイズおよびレスポンスの遅れにおける著しい改善を行う事ができるという事を示した。 彼らは、仕様書のための詳細なレベルでの要求がないような、HTTP 拡張のセットを提案した。 Douglis ら[8] は、リソースが Web 中で変化する割合を計るために完全な HTTP メッセージ内容の追跡について同じセットを使用した。

Marimba, Netscape, Sun, Novell, At Home の各社によって W3C に提案された HTTP Distribution and Replication Protocol (DRP) は、"HTTP を通じたデータの効率的な応答" [13] をサポートするために、HTTP に新しい特徴を持たせるという目的とする。 DRP 提案の一つの特徴として "differentialdownloading" の使用があるが、これは本質的に差分エンコーディングの形式である。 元々の DRP 提案はここに記述されたものとは異なったアプローチを使用するのだが、DRP の将来の改訂ではこの文書中の提案に従うように改訂されるであろう。

Tridgell と Mackerras [28] は "rsync" アルゴリズムについて記述したが、これは差分エンコーディングに似たものを遂げる。 rsync では、クライアントはあるキャッシュエントリを一連の固定したサイズのブロックへと分解し、各ブロックについての digest 値を計算し、そのリクエストの一部としてサーバへその一連の digest 値を送る。 オリジンサーバは同じブロックに基づいた計算を行い、その digest 値が異なるブロックのみを返す。 我々は、この文書の後半に記述される "インスタンス操作" の枠組みを使用する事で rsync をサポートする事が可能であるかもしれないと考えるが、これは詳細が任意の場合に良い結果が出ているわけではない。

2 目標

この提案の目標は以下の通りである:

  1. 待ち時間やネットワークの稼働時間を改善する事によって、HTTP レスポンスの平均サイズを減らす。
  2. 余分なネットワークの往復{round trip} を避ける。
  3. リクエスト毎及びレスポンス毎の負荷{overhead} 量を最小限にする。
  4. 様々なエンコーディングのアルゴリズムやフォーマットをサポートする。
  5. HTTP/1.0 や HTTP/1.1 と相互動作しうる。
  6. クライアントやプロクシ、サーバについて、完全にオプショナルである。
  7. 適度に単純な実装を許可する。

目標には以下のものは含まれない:

この仕様書中には、特に PUT リクエストのボディのための差分エンコーディングの使用を排除するようなものはない。 しかし、サーバがそのようなメッセージを解釈できるかどうかをクライアントが発見するためのメカニズムは現在存在しないので、それらがどのように使用されるかという事を詳述する事はしない。

3 専門用語

HTTP/1.1 [10] は以下の語を定義する:

リソース{resource}
section 3.2 にて定義されるような、URI によって判別されるネットワークデータオブジェクト、あるいはサービス。 リソースは複数の表現 (例えば、複数の言語、データフォーマット、サイズ、解像度等) で利用したり、別の方法で変更したりできる。
エンティティ{entity}
リクエストやレスポンスの付加物{payload} として転送される情報。 エンティティは、section 7 で記述されるように、エンティティヘッダフィールドという形での外部情報と、エンティティボディという形での内容から成る。
バリアント{variant}
リソースはどの瞬間においても一つ、あるいは複数の、それに関連付けられた表現を持っている。 それらの表現のそれぞれを `バリアント' と呼ぶ。 `バリアント' という語の使用が、そのリソースが内容ネゴシエーションされているという事を意図するわけではない。

"entity" の辞書による定義は、"その存在や対象、あるいは概念的現実が他と明確に区別されるもの" である [21]。 不幸にも、HTTP/1.1 中の "entity"の定義は、MIME [12] 中で使用されるそれに似ており、MIME と HTTP との誤った類推に基づくものである。

MIME では、電子メールはメッセージとは区別されるものを持っている。 MIME は "エンティティ" を "特に MIME にて定義されたヘッダフィールドと、あるメッセージかマルチパートメッセージのボディ中の一部分のいずれかの内容を参照する" ようなものとして定義している。

しかし HTTP では、GET へのレスポンスはメッセージとは区別されるものを持ってはいない。 むしろ、それはリソース (あるいはある制約のセットに従うようなバリアント) の現状を反映する。 HTTP/1.1 仕様書では、"現時点において特定されたリソースの選択されたバリアントについて GET リクエストへのレスポンスとして返される値" について記述するための用語はない。 これは、この概念が必要な場所において HTTP/1.1 仕様書中で不適切な表現に通じる。

この概念を表現するために、我々はこの文書に使用するための新しい用語を定義する:

インスタンス{instance}
現時点において、特定されたリソースの選択されたバリアントについて、0 以上の内容コーディングが適用されているが、あらゆるインスタンス操作 (以下参照) や転送コーディングは適用されていないような、GET リクエストに対して、ステータス 200 レスポンス中にて返されるであろうエンティティ。

HTTP/1.1 では、エンティティよりも、インスタンスに関係しているので、エンティティタグについて考える事は便利である。 すなわち、与えられたリソースについて、二つの異なるレスポンスメッセージが同じエンティティタグを持っているかもしれないが、リソースの二つの異なるインスンスは決して同じ (強い) エンティティタグに対応すべきではない。

我々は、この文書にて、二つのインスタンス間の違いとしてエンコードされた HTTP レスポンスを表すために、"差分" という用語を非公式に使用する。

より形式的に言えば、差分エンコーディングは、この新しい用語に結びついた、潜在的にインスタンス上の変形のより大きなクラスのメンバーである:

インスタンス操作{instance manipulation}
部分中、あるいは複数のレスポンスメッセージ中のサーバからクライアントへ運ばれているインスタンスになるであろう一つ以上のインスタンスへの操作。 例えば、範囲選択や差分エンコーディングである。 インスタンス操作はエンドトゥエンドで行われ、しばしばクライアントにてキャッシュの使用を必要とする。

後に明らかになるような理由のため、インスタンス操作の形式として部分範囲選択に関して考える事は便利である。 また、いくつかの状況では、圧縮も内容コーディングや転送コーディングとしてではなく、インスタンス操作として扱われるかもしれない。

4 HTTP メッセージ生成シーケンス

HTTP/1.1 は、様々な異なる形のボディの値をサポートする:

内容コーディング{Content-coding}
仕様書によると、"内容コーディング値は、エンティティに適用されている、もしくは適用できるエンコーディング変換を示す。 内容コーディングは、文書をその根本的なメディアタイプのアイデンティティを失ったり、情報の欠落する事が無いように、圧縮したり、他の有用な変換が行われる事を許可するために、主に使用される。 しばしば、エンティティはコード化された形態で保存され、直接転送され、受け取り側によってのみデコードされる" とある。 内容コーディングは通常エンドトゥエンドでの変形である;すなわち、一度送信者によって適用されたら、それは最終受信者以外には取り除かれる事はない。 中間のサーバは、適切な状況下では、内容コーディングを適用してもよい。
転送コーディング{Transfer-coding}
仕様書によると、"転送コーディング値は、ネットワークを通して "安全な転送" を保証するために、エンティティボディに適用されている、する事のできる、する必要のあるエンコーディング変換を示すために使われる。 転送コーディングは、元のエンティティではなくメッセージの特性である、という点で内容コーディングとは異なる" とある。 転送コーディングは明示的にホップバイホップの変形である (しかし、最適化として、中間のプロクシは、その振る舞いがその外部に見えている機能とは矛盾しない場合、メッセージの転送コード化されたバージョンを保存する事ができる) 。
範囲{Ranges}
Range ヘッダを使用する HTTP クライアントは、サーバにインスタンス値全体ではなく、インスタンスの一つ以上の部分範囲を返すようにリクエストできる。 (文書の章のようにして) 他の種類の範囲仕様の作成者によって将来的に拡張が許可される可能性はあるけれども、HTTP/1.1 は byte-ranges のみをサポートする。

クライアントは、その値に理解できる内容コーディングのセットのリストを含んだ、"Accept-Encoding" ヘッダを送信する事によって内容コーディングを受け取る事ができるという事を知らせる。 そこには、どの内容コーディングを望むかについての情報を自由に含んでもよい。 もしサーバが identity 以外の内容コーディングを使用する場合、レスポンス中に適用されている順の内容コーディングのリストを含んだ、"Content-Encoding" ヘッダフィールドを含む。

RFC 2068 [9] では、そのレスポンスを特徴づけるために同様な "Transfer-Encoding" ヘッダを含んでいるが、転送コーディングの使用についての折衝のための類似したメカニズムは含んでいなかった。 そこで HTTP/1.1 [10] から、新しく "Accept-Encoding" と類似する "TE" ヘッダが加えられた。

この文書にて、我々はインスタンス操作の使用をサポートするために、新しいオプショナルなメッセージヘッダを加える。 クライアントは、"Accept-Encoding" に類似した、"A-IM" ヘッダ ("Accept-Instance-Manipulation" と記述するのは長すぎるので、それの省略形) を送信する事によってそのインスタンス操作を受け取る事ができるという事を知らせる。 同様に、サーバは、"IM" ヘッダを使用して適用したインスタンス操作のセットを列挙する。

クライアントは、差分エンコーディングがどのように HTTP レスポンスに適用されるかを見極めるために二つの変形の関係を理解しなければならない。

概念的に、様々な変形は以下の順で適用される:

  1. GET リクエストを受信する時、サーバはリクエストされたリソースを識別するためのリクエスト中の URI を使用する。
  2. オプショナルで、サーバはリソースのバリアントを選択するためのリクエストからの情報 (またあれば追加的情報) を使用する。
  3. この点で、サーバはインスタンスに identity 以外の内容コーディングを適用しているかもしれないし、あるいはその生成時に既に適用されているかもしれない。 これもまた Content-Encoding ヘッダに示される。
  4. リクエストが成功した場合の、最初の 3 段階の結果がインスタンスである。 インスタンスには、ボディ (空の場合もある) ともしあればインスタンスヘッダを含む。 エンティティタグがあれば、この点に割り当てられている。 すなわち、エンティティタグはエンティティではなく、インスタンスに関係している。
  5. その後、サーバはインスタンス操作を適用する事ができる。 例えば、リクエストが Range ヘッダを含んでいた場合、サーバは、元々のヘッダ、Content-Range ヘッダ、及び (おそらくエンコードされた)ボディからの適切な範囲のセットから成るような、部分レスポンスを自由に生成する事ができる。 差分エンコーディングとはインスタンス操作であり、またこの段階にて計算される。
  6. 第 5 段階の結果は、エンティティヘッダとエンティティボディから成る、エンティティとなる。
  7. その後、サーバは identity 以外の転送コーディングを適用する事ができる; この段階で、データを読み出しながらの圧縮 {on-the-flycompression} を行うだろう。 その場合、Transfer-Encoding ヘッダがメッセージに付加される。
  8. 第 7 段階の結果は、メッセージボディ (エンティティボディが転送コード化されたもの)、エンティティヘッダ、及び更なるレスポンスヘッダや一般ヘッダから成るmメッセージである。

注: HTTP/1.1 仕様書 [10] の section 14.13 では、"Content-Length エンティティヘッダフィールドは、受信者に送られるエンティティボディのサイズを表す" と述べている。 言い換えれば、Content-Length は、バリアントのインスタンスではなく、エンティティの長さを測定する。 例えば、メッセージが差分エンコーディングの場合、Content-Length は現在のインスタンスの長さではなく、差分エンコーディングの長さを与える。

図式化すると、シーケンスは以下のようになる:

 データタイプ    次のデータタイプへ移行するための操作
 ============    ====================================
 リソース
             |   必要であれば、利用可能なバリアントを選択
             v
 バリアント
             |   必要であれば、内容コーディングを適用
             v

             |   エンティティタグを計算/割り当て
             v
 インスタンス
             |   必要であれば、インスタンス操作を適用
             v      (差分エンコーディング, 範囲選択, 等々)
 エンティティボディ
             |   必要であれば、転送コーディングを適用
             v
 メッセージボディ

この HTTP メッセージ生成シーケンスの形式化は以前には記述されていなかった。 しかし、あらゆる内容コーディングが適用され、エンティティタグが割り当てられた後に、またあらゆる転送コーディングが適用される前に、範囲選択が必要がある事は明らかである。 それ故に、この形式化は、以前の慣例や仕様に完全に一致する。

4.1 差分と範囲の間の関係

インスタンス操作の形式に範囲指定と差分エンコーディングの両方がある場合、どちらを最初に適用すべきか? これは範囲指定がどのように使用されているかに依存する。

範囲指定は要求するクライアントの判断によって、主に二つの目的で使用される:

  1. メッセージ通信の早期異常終了{premature termination} の後に部分的レスポンスを完成するために。
  2. インスタンスの選択された部分{section} のみを得るために。

範囲指定の第一の用途では、その使用の意図は差分エンコードされたインスタンスの原型コピーを得る事なので、任意の差分エンコーディングの後に適用されなければならないであろう。 範囲指定の第二の用途では、さもなければ、Range リクエストで指定されたオフセットが無意味である (クライアントは、一般にサーバの差分エンコーディングがインスタンスのバイトオフセットとエンティティのバイトオフセットとをどのように位置付けているかを知る事はできない) だろうから、任意の差分エンコーディングの前に適用されなければならないであろう。

従って、複数の instance-manipulation が適用されるべき順序をクライアントが指定する事を可能にするようなメカニズムが必要である。 これは "A-IM"ヘッダ (section 10.5.3 参照) の仕様の一部としてあっさりと提供されており、そこでは、サーバが instance-manipulation を "A-IM" ヘッダに列挙した順に適用する事を要求する。 また、クライアントが (他の instance-manipulation に対してその順序によって) 範囲選択が差分エンコーディングの前、あるいは後に行われるかどうかを指定する事を可能にするために、登録済みの instance-manipulation のセット中に "range" というリテラルを含んでいる。

更に、複数の instance-manipulation がどの順序で適用されたかを示すためのメカニズムも必要である; これは "IM" ヘッダ (section 10.5.2 参照) の仕様の一部であり、そこでは "Content-Encoding" ヘッダにて使用されたのと同じやり方に従う: "IM" ヘッダは、(おそらく、特別な "range" リテラルを含む) 適用された順に instance-manipulation を列挙する。

ある範囲指定が圧縮と結合する場合に、同様の問題が発生する。 クライアントが、圧縮されたメッセージの未完異常終了の後に部分的レスポンスを完成するために範囲指定を使用している場合、その範囲指定は圧縮の後に適用されなければならないであろう。 これは、その圧縮は内容コーディングとして行う事ができるので、修正されない HTTP/1.1 において実現可能である。 しかし、クライアントがインスタンスの選択された部分を得るために範囲指定を使用している場合、それは通常圧縮されていないバリアントに関してのみオフセットを指定する事ができるであろう。 もし選択された部分が圧縮を主張できる程に十分に大きければ、クライアントは圧縮された転送コーディングを要求する事ができるが、これはホップバイホップな変形であり 、最も効率的なアプローチというわけではない (特に経路に HTTP/1.0 プロクシがある場合)。

この問題は、 instance-manipulation として圧縮の使用を (内容コーディングや転送コーディングと同様に) サポートし、圧縮に関する instance-manipulation が範囲に関する instance-manipulation の後に行われる事をクライアントが指定する事が可能になるような新しいメカニズムを使用する事によって、解決する事ができる。

またこれによって、(UNIX の "diff" コマンドのような) いくつかの単純な異なるアルゴリズムが圧縮後の出力に最良の結果になる事を要求するので、クライアントは圧縮が差分エンコーディングの前後に行われたかどうかを制御する事が可能になる。

5 基本メカニズム

この章では、差分エンコーディングの背景にある概念について説明する。 これは提案される拡張の公式の仕様としては意味されない; それに関しては、section 10 を参照せよ。

5.1 背景: HTTP キャッシュ検証の概要

クライアントがキャッシュにレスポンスを持っており、このキャッシュエントリが最新である事を確認したい場合、HTTP/1.1 ではクライアントが "キャッシュバリディタ" の二つの形式のうちの一つを使用して、"条件付 GET" を行う事ができる。 HTTP/1.0 と HTTP/1.1 の両方で利用可能である従来の形式では、クライアントはサーバが (もしあれば) レスポンスと共に提供した"Last-Modified" タイムスタンプをサーバに提供するために "If-Modified-Since" リクエストヘッダを使用する事ができる。 リソースについてのサーバのタイムスタンプが変わっていなければ、304 (Not Modified) というステータスコードのレスポンスを送る事ができ、そこではリソースのボディを送信しない。 タイムスタンプが変わった場合、サーバは通常 200 (OK) というステータスコードのレスポンスを送り、リソースの完全なるコピーと新しいLast-Modified タイムスタンプを転送する。

このタイムスタンプに基づいたアプローチは、タイムスタンプ解決能力不足のためにエラーになる傾向がある: リソースが一秒間に二度変更した場合、それを検知できないかもしれない。 それ故に、HTTP/1.1 では、サーバがレスポンスと共にエンティティタグを供給する事も可能にした。 エンティティタグはそれ自体は読んでも意味のわからない{opaque} 文字列であり、それが必要なサーバによって構築されるものである; プロトコル仕様では、エンティティタグの必要条件には必要最低限のものしか課さない。 (特に、"強い" エンティティタグは、リソースの値が変わる時には必ず変更されなければならない。 ) この場合、クライアントは、キャッシュされたレスポンスに対応したエンティティタグを提示するための、"If-None-Match" リクエストヘッダを使用して条件付リクエストを送信する事によって自身のキャッシュエントリを検証する事ができる。 (プロトコルでは、他にも "If-Range" ヘッダのような、この他に必要な往復作業を省くするために使用される、エンティティタグを転送するための方法をいくつか定義している。 ) 提示されたエンティティタグがそのリソースについてのサーバの現在のタグと一致する場合、サーバは 304 (NotModified) レスポンスを送るべきである。 そうでない場合、サーバは 200(OK) レスポンスと、リソースの完全なるコピーを送るべきである。

既存の HTTP プロトコル (HTTP/1.0 や HTTP/1.1) では、条件付リクエストを送るクライアントは、以下の二つのレスポンスのいずれかが期待できる:

非公式には、これらを、それぞれ 100% と 0% の "差分" とみなす事ができる。 これらの差分は、特定のキャッシュレスポンスに関係がある事に注目せよ。 すなわち、クライアントはリソースの二つのインスタンスがどのように異なっているかを特定せずに差分を要求する事はできない。 "新しい" インスタンスとは暗黙的にサーバが無条件リクエスト時に返す現在のインスタンスであり、"古い" インスタンスとは現在クライアントのキャッシュにあるものである。 キャッシュバリディタ (最終更新時刻やエンティティタグ) は、サーバに古いインスタンスの同一性を伝えるために使用されるものである。

5.2 差分の転送を要求する事

実際の差分の転送をサポートするために、HTTP/1.1 の拡張では以下の特性が与えられる必要がある:

  1. リクエストが条件付きであると記述するための方法。
  2. その差分がクライアントによって適用されるであろう、古いインスタンスを指定するための方法
  3. クライアントが差分エンコーディングの一つ以上の特定の形式を適用する事ができる事を示すための方法。
  4. 特定のフォーマットにて差分エンコードされているようなレスポンスを記述するための方法。

最初の二つの特性は既に HTTP/1.1 にて提供されている: ("If-Modified-Since" や "If-None-Match" のような) 条件付きリクエストヘッダがある事によってリクエストが条件付きと記述されるし、そのヘッダの値が (last-modified タイムスタンプの粒状性{granularity} の問題を無視して) 古いインスタンスを一意に指定する。

四番目の機能についての議論は、section 5.6 まで置いておく。

三番目の特性、すなわちクライアントが (平凡な 0% 及び 100% の差分を除いて) 差分に適用できるという事を示すための方法は、リクエストヘッダフィールド、特に "A-IM" ヘッダ中に、受信可能な差分エンコーディングのフォーマットのリストを含め転送する事によって達成する事ができる。 条件付リクエスト中にこのリストがある事によって、クライアントは差分エンコードされたキャッシュの更新に適用する事ができるという事を示す。

例えば、クライアントは以下のリクエストを送る事ができる:

 GET /foo.html HTTP/1.1
 Host: bar.example.net
 If-None-Match: "123xyz"
 A-IM: vcdiff, diffe, gzip

このリクエストの意味は以下の通りである:

この例において、そのリソースについてのサーバの現在のエンティティタグがまだ "123xyz" である場合、従来のサーバのように、単に 304 (NotModified) レスポンスを返すべきである。

エンティティタグが変わっている場合、必ずしもそうではないがリソースが変更されたと推測されるので、その代わりにサーバはエンティティタグが "123xyz" であったインスタンスと現在のインスタンスの間の差分を計算するであろう。

差分を計算するために、サーバが保存する必要があるものについての議論は、section 7 まで置いておく。

クライアントは差分の受信の希望を示しているが、サーバはその instance-manipulation の形式をサポートしていないような場合、サーバは単にリクエストのこの部分を無視するであろう、という事に注意せよ。 (HTTP では、仕様によって実装が従う必要がないとされるヘッダを実装が無視する事を常に認めているし、"A-IM" の仕様はサーバが理解しない instance-manipulationを無視する事を認めている。 ) そのため、サーバが A-IM ヘッダを全く実装していないか、あるいは A-IM ヘッダに列挙されたインスタンス操作のいずれも実装していないような場合、サーバはまるでクライアントが差分エンコードされたレスポンスを要求しなかったかのように振る舞う: すなわち、サーバはステータス 200 レスポンスを生成する。

5.3 差分のアルゴリズムとフォーマットの選択

サーバは、差分エンコードされたレスポンスを転送する事を要求されない。 例えば、その結果はそのリソースの現在のサイズより大きいかもしれない。 サーバはそのリソースの種類 (例えば、圧縮されたバイナリフォーマット)についての差分を計算できないかもしれない; あるいは、サーバは差分の計算のための十分な CPU サイクルを持っていないかもしれない; あるいは、サーバはクライアントによってサポートされた差分フォーマットのいずれもサポートしていないかもしれない; あるいは、差分の計算に伴う遅れがより小さなレスポンスを送信する事により回避される遅れほど価値がない程に、そのネットワーク帯域幅は十分に広いのかもしれない。

しかし、サーバが差分を計算したい時に、それがサポートするエンコーディングのセットとクライアントによって提示されたセットとの間に複数共通するエンコーディングがある場合、どのエンコーディングを使用すべきか? クライアントは "A-IM" ヘッダ中に "品質値" (あるいは "qvalues") を使用する事で優先度を表現する事ができるが、これはほとんどサーバのオプションである。 HTTP/1.1 仕様書 [10] では、qvalues についてより詳細に記述している。 (あるフォーマットについてそれをデコードするためのコストがより低く、クライアントがリソースについて制限が課されている{resource-constrained} ような場合、クライアントはより小さなエンコーディングを成すような差分エンコーディングフォーマットとは違うものを望むかもしれない。 )

サーバ実装は多くのアプローチ能力を持っている。 例えば、CPU サイクルは豊富だがネットワーク帯域幅が不足するような場合、サーバは利用可能なエンコーディングの各々を計算し、最も小さな結果を送る事ができる。 あるいは、サーバは、リソースの content-type や、リソースの現在のサイズ、及びリソースのインスタンス間での予測される変化量等に基づいた、エンコーディングフォーマットを選択するための解決手法{heuristics} を使用する事ができる。

一般的にあるリソースがそれが変更された間にいくつかの異なる差分に対応するクライアントによって要求される場合、サーバに差分を内部にキャッシュする事は利益になるであろうという事に注意せよ。 この場合、差分を計算するコストは多くのレスポンスに関して償却されるであろうから、サーバはより高価な計算を使用する事ができる。

5.4 差分エンコードされたレスポンスの識別

差分エンコーディングを使用するレスポンスは、そういうものであると識別されなければならない。 これは "IM" レスポンスヘッダを使用して成され、section 10.5.2 に詳述される。

しかし、差分エンコードされたレスポンスが差分メカニズムを認識しないような中継の (プロクシ) キャッシュを通じて流れる場合、このアプローチを単純化したようなアプリケーションは重大な問題を引き起こす事になるであろう。 インターネット上には未だにかなりの数の HTTP/1.0 キャッシュがあり、それらは全く置き換えられないかもしれないし、また HTTP の仕様ではメッセージ受信者は自身が理解できないようなあらゆるヘッダフィールドを無視する事を要求しているので、差分に対応していないプロクシキャッシュが差分エンコードされたレスポンスを受け取った時にそのレスポンスを保存し、後にその同じリソースへとリクエストをした差分に対応していないクライアントにそれを返してしまうかもしれない。 この単純なクライアントは、予測可能なように不快な結果を伴って、自身が資源全体の有効なコピーを受け取ったと信じるであろう。

この問題を解決するために、差分エンコードされたレスポンス (実際には、全ての instance-manipulation がなされたレスポンス) は、新しい HTTP ステータスコードを使用する事で識別されるという事を提案する。 以下の議論における特性について、(現在割り当てられていない) 226 というコードと、"IM Used" という説明句を使用する。 ("Instance Manipulation Used" と完全に記述しても、これは不必要なバイトの送信を要求し、またこの説明句は通常人間のユーザによって見せるべきではないので、そうする事による利点はないだろう。 ) このアプローチにはいくつかの先例がある: HTTP/1.1 の仕様では、リソースの部分範囲の送信のために、206 (Partial Content) ステータスコードを導入している。 既存のプロクシは、未知のステータスコードを持つレスポンスは明らかに転送して、それらをキャッシュしようとはしない。

この新しいステータスコードの使用するためには、レスポンスを保存するHTTP/1.0 キャッシュを避けるために "Expires" ヘッダを使用し、より新しいキャッシュが差分エンコードされたレスポンスを保存できるようにするために (HTTP/1.1 にて定義される) "Cache-Control: max-age" を使用する必要があるだろう。 これはレスポンスヘッダに多くのバイト数を加えるので、差分エンコーディングの有効性を減らしてしまうだろう。 また、このアプローチが全ての HTTP/1.0 プロクシによる全てのキャッシュを抑える事が完全に明らかになっているわけではない。

我々は追加的ステータスコードを差分エンコーディングのサポートの一部として定義したくはなかった。 しかし、HTTP/1.0 キャッシュ実装の展開との互換性を保たせるための効率的な方法を他に見つけられない。

5.5 キャッシュの安全性を保証する事

我々は 未知の 2xx ステータスコードを持つレスポンスをキャッシュしようとするあらゆる HTTP/1.1 プロクシ実装には気づかないが、HTTP/1.1 の仕様では、レスポンスが明示的にキャッシングを許すようなExpires や Cache-Control ヘッダフィールドを転送する場合には、この振る舞いを許す。 226 (IM Used) レスポンスがそのようなヘッダを転送する時、これは問題を生じさせるであろう。

この場合の解決策は、HTTP/1.1 の仕様からのキャッシュコントロール拡張メカニズムを開発する事である。 我々は新しいキャッシュ指示子である "im"を定義する。 これは、"no-store" キャッシュ指示子は IM や A-IM ヘッダの仕様に従う実装によって無視されるであろうという事を示す。

例えば、以下のレスポンス:

 HTTP/1.1 226 IM Used
 ETag: "489uhw"
 IM: vcdiff
 Date: Tue, 25 Nov 1997 18:30:05 GMT
 Cache-Control: no-store, im, max-age=30

 ...

これは、HTTP/1.1 の仕様 (そこでは max-age キャッシュ指示子について、"その他にキャッシュに制限を与えるような指示子が無ければ、レスポンスはキャッシュ可能 [...] であるという事を暗黙的に意味する。 " と記述している) に従うキャッシュによって保存され "てはならない"。 しかし、im キャッシュ指示子についての仕様に従うキャッシュ (すなわち、A-IM やIM ヘッダフィールド、そして 226 ステータスコードについての仕様に従うキャッシュ) は no-store 指示子を無視し、それ故キャッシングを可能にするとしてmax-age 指示子を見る。

我々は、全ての HTTP/1.1 キャッシュが max-age 指示子が no-store 指示子によって上書きされる規則に従っているという事を完全に確証できるわけではない。 運用上の試験によってこれが問題であるとされた場合、より入念な解決策をとる事が可能となる。

オリジンサーバ実装者に対する警告: ステータス 226 レスポンス中に以下を送ってもそれで十分ではない。

 Vary: If-None-Match, A-IM

我々は、これでは IM や A-IM を実装しないプロクシキャッシュがキャッシュされた 226 レスポンスを不正確に "有効にする事" を防げないという少なくとも一つの筋書きを発見した。

5.6 差分エンコードされたレスポンスの転送

差分エンコードされたレスポンスは、四つの点において標準のレスポンスと異なる:

  1. 226 (IM Used) というステータスコードを転送する。
  2. このレスポンス中にどの差分エンコーディングが使用されるかを示している、"IM" レスポンスヘッダーフィールドを転送する。
  3. そのメッセージボディはインスタンスの完全なるコピーではなく、現在のインスタンスの差分エンコーディングである。
  4. この文書の後に記述されるように、いくつかの他の新しいヘッダを転送する事ができる。

例えば、section 5.2 にて与えられたリクエストに対するレスポンスは以下のものに似て見えるかもしれない:

 HTTP/1.1 226 IM Used
 ETag: "489uhw"
 IM: vcdiff
 Date: Tue, 25 Nov 1997 18:30:05 GMT

 ...

(これはバイナリフォーマットなので、レスポンスボディの実際の内容を見る事はできない。)

注: 差分エンコーディングを伴う 226 レスポンス中の Etag ヘッダは、リソースのバリアントの現在のインスタンスのエンティティタグを提供する。 インスタンスではなく、差分値にエンティティタグを対応させる事には意味がない。

5.7 範囲指定と差分エンコーディングを組み合わせたリクエストの例

section 5.2 にて使用された例では、クライアントは以下のものを送る:

 GET /foo.html HTTP/1.1
 Host: bar.example.net
 If-None-Match: "123xyz"
 A-IM: vcdiff, diffe, gzip

そしてサーバは 304 (Not Modified) レスポンスか適切な差分エンコーディングを返す。

ここでは、クライアントがリクエストをどのように解釈すべきかを明確にするために更なる例をいくつか示す。

 GET /foo.html HTTP/1.1
 Host: bar.example.net
 If-None-Match: "123xyz"
 A-IM: vcdiff, diffe, gzip, range
 Range: bytes=0-99

この意味は、差分エンコーディングが (もしあれば圧縮も) 計算された後、サーバが差分エンコーディングの先頭 100 バイトだけを返すという事を除いて、上記の例と同じである。 (もしそれが 100 バイトより短かければ、差分エンコーディング全体が返される。) "range" トークンが "A-IM" ヘッダ中の最後に見られるので、これはオリジンサーバにあらゆる範囲選択は他のinstance-manipulation の後に適用するように指示している。

If-Range メカニズムと差分エンコーディングの間の相互動作は多少複雑である。 (If-Range は、非公式には、"エンティティが変わっていなければ、私が失っている部分を送れ; そうでなければ、新しいエンティティ全体を送れ。 "という意味を持つ。 ) ここでは、この組み合わせの使用を明確にすべき例を示す。

クライアントは http://bar.example.net/foo.html の現在の完全なるインスタンスを得たいと仮定する。 それは既にこの URI についての (完全な) キャッシュエントリと、エンティティタグ "A" を持っており、そのため以下のリクエストを発行する:

 GET /foo.html HTTP/1.1
 host: bar.example.net
 If-None-Match: "A"
 A-IM: vcdiff

サーバの現在のインスタンスはエンティティタグ "B" を持っており、またエンティティタグ "A" を持つインスタンスのコピーもまだ残っている、と仮定する。 その後、サーバは "B" と "A" の間の差を計算し、以下のように応答するであろう:

 HTTP/1.1 226 IM Used
 Etag: "B"
 IM: vcdiff
 Date: Tue, 25 Nov 1997 18:30:05 GMT
 Content-Length: 1000

 ...

しかし、クライアントが差分エンコードされた内容のためのメッセージボディをちょうど 900 バイト受信した後ネットワーク接続が終了した。

クライアントは、中断されたレスポンスで送られていた差分エンコーディングの残る 100 バイトを取得したい。 従って、以下のものを送るべきである:

 GET /foo.html HTTP/1.1
 host: bar.example.net
 If-None-Match: "A"
 If-Range: "B"
 A-IM: vcdiff,range
 Range: bytes=900-

このやや入念なリクエストは十分に定義された意味を持っており、それはサーバがリクエストを受信する時に、インスタンスの現在のエンティティタグTcur に依存する:

Tcur = "A"
(すなわち、ある理由により、インスタンスは既にクライアントのキャッシュ内の値に戻った)。 サーバは、"If-None-Match" について HTTP/1.1 の仕様に要求されるように、304 (Not Modified) レスポンスを返すべきである
Tcur = "B"
(すなわち、インスタンスは再び変わっていない)。 この場合、"If-None-Match" について HTTP/1.1 仕様書には (差分エンコーディングを理解しないサーバによって) そのヘッダフィールドは無視されるとある。 従って、vcdiff インスタンス操作の後に範囲選択が適用される (両方が適用される事になっている場合) を除いて、これは以前のクライアントのリクエストと等価である。 そのため、(差分を認識する) サーバは、"A" インスタンスと "B" インスタンス間間の差分を計算 (あるいはキャッシュされた差分の計算を使用) し、その後範囲選択を適用し、vcdiff エンコーディングの結果のバイト 900 から 999 までを含むメッセージボディと、"IM:vcdiff,range" レスポンスヘッダを伴う、226 (IM Used) レスポンスを返す。
Tcur = "C"
(すなわち、インスタンスは再び変わった)。 この場合、"If-None-Match" について HTTP/1.1 仕様書には、これは現在のインスタンスについての無条件リクエストと等価であるとされる。 "If-Range" についての仕様は、サーバに現在のインスタンス全体を返す事を要求する。 しかし、差分を認識するサーバは、"If-None-Match" フィールドによって記述された "A" インスタンスと現在の ("C") インスタンス間の差分を構築し、"IM:vcdiff,range" レスポンスヘッダを伴う、226 (IM Used) レスポンスを返す。

クライアントのリクエストが "If-None-Match: "A"" ヘッダフィールドを含んでいなければ、どのインスタンス全体がクライアントにとって既に利用可能であるかを知らないので、サーバは差分を計算できないであろう。 リクエストが "If-Range: "B"" ヘッダフィールドを含んでいなければ、サーバは後の二つの場合 (Tcur="B" あるいは Tcur="C") を区別する事ができず、差分エンコーディングの結果に範囲選択を適用する事ができないであろう。

一方で、クライアントが http://bar.example.net/foo.html の "A" インスタンスについてのキャッシュエントリを持っており、また (恐らく異常終了した転送の結果) 新しいインスタンス "B" の先頭 900 バイトを既に受信していると仮定する。 今クライアントは現在のインスタンス全体を受信したいので、以下のリクエストを送るであろう:

 GET /foo.html HTTP/1.1
 host: bar.example.net
 If-None-Match: "A"
 If-Range: "B"
 A-IM: range,vcdiff
 Range: bytes=900-

この例においては、以前の例のように、Tcur = "A" ならばサーバは 304(Not Modified) を送るべきだし、Tcur = "C" ならばサーバは、200 レスポンスのように、あるいはインスタンス "A" に対する差分エンコーディングのように、新しいインスタンス全体を送るべきである。

しかし、Tcur = "B" の場合、サーバは、まずインスタンス "A" 及び "B" の両方から指定された範囲 (バイト 900 から終点まで) を選択し、これらの範囲の間の差分エンコーディングを (vcdiffを使用して) 計算し、その後"IM:range,vcdiff" レスポンスヘッダを持つ 226 (IM Used) レスポンスを使用した結果を送信すべきである。

6 エンコーディングのアルゴリズムとフォーマット

いくつもの差分エンコーディングのアルゴリズムとフォーマットが、文献に記述されている:

diff -e
UNIX の "diff" プログラムはいたる所で利用可能であり、エンコーディングとデコーディングの速度が相対的に速い(デコーディングは実際には "ed" プログラムを使用して行われる)。 しかし、差分の結果のサイズは相対的に大きい。 このアルゴリズムはテキストフォーマットにのみ使用可能である。
diff -e | gzip
"diff" の出力を "gzip" [5] (あるいは、"deflate" [7, 6] ならばおそらくなお良い) のようなアルゴリズムによって圧縮する事は、よりコンパクトなエンコーディングを出力するが、エンコーディングやデコーディングのコストは"diff" によるものよりは高くなるであろう。 このアルゴリズムはテキストフォーマットにのみ使用可能である。
vcdiff (vdelta)
"vcdiff" フォーマット [19, 20] を生成するアルゴリズムは本質的にその出力を圧縮し、一般に "diff" と "gzip"の組み合わせによる出力よりも小さくなる。 またこのアルゴリズムは実行が早く、バイナリフォーマット入力にも適用できる。 "vcdiff" フォーマットは以前 "vdelta" と名付けられたアルゴリズムへの作業に基づいている。 ("vcdiff"フォーマットは、差分エンコーディングや圧縮されたフォーマットにも使用できるので、もしその使用が圧縮フォーマットとして採用されるならば、二つの異なる instance-manipulation の使用を区別するために、二つの値が登録される必要がある。 ) 最近発表された研究では、"vdelta" は総合的に最良の差分アルゴリズムであるとしている [16]
gdiff
gdiff フォーマット [14] は、差分を表現するために、一般的でアルゴリズムから独立したフォーマットとして指定された。 これはより一般的なものなので実装も容易だが、それは最もコンパクトなエンコーディングフォーマットではないかもしれない。

この提案では特定のアルゴリズムやフォーマットを推奨しないが、クライアントやサーバの実装者に最も適切なものを選ぶように促す。 しかし、極端に長い "A-IM" ヘッダの可能性を避けるため、我々は、いくらかの実験期間の後、汎用の HTTP 実装のための差分フォーマットの "推奨" セットを明示する事は合理的かもしれないと考える。

我々は、GIF や JPEG のような、典型的な画像エンコーディングの使用に適切な差分エンコーディングアルゴリズムを開発する事が可能であるべきだ、という事には疑問に感じる。 vdelta についての実験は高い可能性を示すものではない [23] けれども、これらのエンコーディングの既に圧縮された形式に直接 vdelta を使用したので、これは単純であるかもしれない。 しかし、画像の二次元の性質を認識する差分エンコーディングアルゴリズムを開発する必要はあるかもしれない。 MPEG 圧縮はビデオストリームの連続のフレーム間の差分の計算に依存するので、これは可能であると期待する事はできる。

7 基点インスタンス{base instances} の管理

資源の修正間の時間がクライアントのキャッシュ中のレスポンスのための一般的な廃棄時間未満である場合、これはクライアントの条件付リクエスト中に示された "古いインスタンス" が最新のインスタンスを参照しないかもしれないという事を意味する。 これにより、サーバがリソースのインスタンスを保持している場合、どれ位古いものを持ち続けるべきかという問題が生じる。 我々はこの古いインスタンスを "基点インスタンス{base instances}"と呼ぶ。

サーバ実装者のために多くの利用可能なオプションがある。 例えば:

サーバは以前のインスタンスを明示的に保存する必要がないかもしれない。 その代わり、特定の基点インスタンスと後のインスタンス間の差分 (あるいは基点インスタンスと以前のインスタンスの逆差分) のみを保存するかもしれない。 このアプローチは計算された差分のキャッシュに集約されるであろう。

これらのアプローチはいずれも追加的なプロトコルサポートを必要とはしない。 しかし、サーバ管理者は以前のインスタンスの部分集合のみを保存したいが、サーバにできるだけ頻繁に差分を使用して応答できるようにしたければ、クライアントはいくつかの追加的な情報を必要とする。 さもなければ、クライアントの "If-None-Match" ヘッダは、例え適切な基点インスタンスがクライアントキャッシュ中に保持されても、サーバに保存されない基点インスタンスを指定するかもしれない。

この問題を解決するために、二つの追加的プロトコル変更を確認する。

7.1 If-None-Match ヘッダ中の複数のエンティティタグ

これまでの例では "If-None-Match" ヘッダ中に一つだけエンティティタグがあったが、HTTP/1.1 仕様ではヘッダが複数のエンティティタグを転送する事が可能である。 この特性はリソースの複数のバリアントの効率的なキャッシングをサポートするために HTTP/1.1 中に含まれていたが、これはその使用法に制限されない。

クライアントが自身のキャッシュ中にあるリソースの複数のインスタンスを持っていると仮定する。 すなわち、それは最新のインスタンスだけでなく、それより一代以上前の、妥当でないインスタンスも持っているという事である。 (あるいは、より古いインスタンスを再構築するための十分な差分あるいは逆差分の情報を持っているかもしれない。 ) この場合、クライアントは自身が差分を適用できるような全てのインスタンスに関してサーバに伝えるために条件付リクエストを使用する事ができる。 例えば、クライアントは以下のようなものを送る事ができる:

 GET /foo.html HTTP/1.1
 host: bar.example.net
 If-None-Match: "123xyz", "337pey", "489uhw"
 A-IM: vcdiff

この場合、自身のキャッシュ中にこのリソースについて三つのインスタンスを持っているという事を示す。 もしサーバがこれらの以前のインスタンスのうちのいずれかの差分を生成する事ができれば、適切な基点インスタンスを選択し、差分を計算し、クライアントに結果を返す事ができる。

しかし、この場合、サーバはクライアントにどの基点インスタンスが使用されているかを伝えなければならないので、我々はこの目的のために、"Delta-Base" という名のレスポンスヘッダを定義する必要がある。 例えば、サーバは以下のようなものを返す事ができる:

 HTTP/1.1 226 IM Used
 ETag: "1acl059"
 IM: vcdiff
 Delta-Base: "337pey"
 Date: Tue, 25 Nov 1997 18:30:05 GMT

このレスポンスは、エンティティタグ "337pey" を持つキャッシュされたレスポンスにデルタを適用し、その結果にエンティティタグ "1acl059" を対応させるようにクライアントに伝える。

もちろん、サーバがクライアントによって識別された以前のインスタンスを複数保持している場合、サーバは差分フォーマットだけでなく、使用する基点インスタンスの選択をする事になるので、返すための最適の差分を選択する問題は複雑になるだろう。

7.2 クライアントのキャッシュを管理するためのヒント

基点インスタンスの選択における複数のエンティティタグをサポートする事で、クライアントは自身のキャッシュ中にリソースの複数の古いインスタンスを保存する事で利益を得るであろう事を暗黙的に意味する。 保存空間が限られているクライアントは全ての古いインスタンスを持とうとはしないだろうから、将来の差分に最も有用であろうインスタンスを保存する事でその有効性を最大にするように自身のキャッシュを管理しなければならない。 これはクライアントへの純粋にローカルな情報を使用する事で達成されるかもしれない (例えば、LRU アルゴリズム) が、サーバーからのあるヒント情報が自身のキャッシュを管理するためのクライアントの能力を改善するかもしれない。 Web キャッシュパフォーマンスを改善するためのヒントの使用については以前に記述されている [4, 22]。

もしサーバがある特定のインスタンスを保持するつもりならば、サーバは保持されるインスタンスを転送するようなレスポンスにラベリングする事ができる。 これは、将来において有用であるかもしれないものは以前のインスタンスのうちのいくつかだけであるという可能性から過去のインスタンス全てを保持する必要がないので、クライアントが自身のキャッシュを管理する助けになるだろう。 このラベルはクライアントに対するヒントであり、サーバが無期限にインスタンスを保持するという約束ではない。

この目的のために、既存の "Cache-Control" ヘッダに、"retain" という名の新しい指示子を加える事を提案する。 例えば、無条件のリクエストへのレスポンス中にて、サーバは以下のようなものを返す事ができる:

 HTTP/1.1 200 OK
 ETag: "337pey"
 Date: Tue, 25 Nov 1997 18:30:05 GMT
 Cache-Control: retain

これは、差分に対応するクライアントはこのインスタンスを保持すべきであるという事を表している。 また "retain" 指示子は、現在のインスタンスを参照するような、差分レスポンス中に現す事ができる:

 HTTP/1.1 226 IM Used
 ETag: "1acl059"
 Date: Tue, 25 Nov 1997 18:30:05 GMT
 Cache-Control: retain
 IM: vcdiffDelta-Base: "337pey"

"retain" 指示子は、オプショナルでタイムアウトパラメータを含んでおり、これはサーバが特定の時間に古い基点インスタンスを削除する事を予測している場合に使う事ができる。 例えば、

 HTTP/1.1 200 OK
 ETag: "337pey"
 Date: Tue, 25 Nov 1997 18:30:05 GMT
 Cache-Control: retain=3600

これは、サーバが一時間この基点インスタンスを保持するつもりであるという事を意味する。

サーバがクライアントにヒントを提供する事ができるようなもう一つの状況として、サーバは一般に差分メカニズムをサポートするが、特別のリソースにおいては差分エンコードされたレスポンスを供給するつもりはないような場合がある。 "retain=0" という指示子を送る事によって、クライアントは、この基点インスタンス (そして暗黙的に、このリソース) を使用して、差分エンコードされたレスポンスを得ようとしてリクエストヘッダバイトを無駄使いすべきではないという事を表す。 これは更に、クライアントはこれが古くなった後は、このインスタンスをもってキャッシュ空間を無駄使いすべきではないという事も表す。 レスポンスヘッダバイトの無駄使いを回避するために、サーバは差分エンコードされたレスポンスを得ようとするリクエストへの応答以外には、"retain=0" を送るべきでない。

"retain" 指示子は "max-age" 指示子と直交性{orthogonal} を持つ事に注意せよ。 "max-age" 指示子は、キャッシュエントリがどれくらいの時間新鮮であるか (すなわち、再確認のためにオリジンサーバと連絡をとらずに使用する事ができるか) を示す; これに対し、"retain" 指示子はクラキャッシュエントリが古くなった後にクライアントが関心を持つものである。

実際には、"Cache-Control" レスポンスヘッダフィールドは既にあるかもしれないので、この指示子を送る (バイト上の) コストはこれらの例が示すものよりも小さいかもしれない。

8 差分と中間キャッシュ

我々は差分エンコードされたレスポンスが無配慮なプロクシキャッシュに保存されないように設計したが、プロクシが差分メカニズムを理解する場合、それが差分の送受信に関与する事は有益かもしれない。

プロクシはいくつかの独立した方法で関与する事ができる:

これらのオプション技術は全てプロクシソフトウェアの複雑さを増大させ、またプロクシの記憶装置や CPU 要件をも増大させるかもしれない。 しかし、これらは注意深く適用されれば、エンドユーザに見られる待ち時間やネットワーク上の負荷を縮小する助けとなるであろう。 一般に、CPU 速度とディスクコストの改善速度は、ネットワーク待ち時間のそれよりも速いので、我々は複雑なプロクシ実装から利用可能な値は増えていくと見ている。

9 データの完全性のダイジェスト

受信者がいくつかの個別のメッセージから完全な HTTP レスポンスを再結合する場合、そのレスポンスの完全性を確認する事が必要であろう。 例えば、クライアントのキャッシュが汚染されていたり、あるいは (クライアントやサーバの) 差分エンコーディングの実装がバグを持っているかもしれない。

HTTP/1.1 では個別のメッセージの完全性を保証するためにメカニズムを含んでいる。 メッセージには "Content-MD5" レスポンスヘッダを含む事ができ、メッセージのボディ (ヘッダではない) の MD5 メッセージダイジェストを提供する。 ダイジェスト認証メカニズム [11] は、それが特定のヘッダフィールドを含んでいる事以外、同様のメッセージダイジェスト関数を提供する。 これらのメカニズムはどちらも、差分エンコードされたレスポンス (あるいは、さらに言えば、範囲指定レスポンス) を適用する結果の場合のように、いくつかのメッセージを通じて転送されたデータのセットをカバーするためのものは何も提供されない。

再結合されたメッセージのためのデータの完全性については、新しいメッセージヘッダの導入を必要とする。 そのようなメカニズムは、別の文書 [24]にて提案されている。 不当な書き換えから差分メッセージを保護するために、ダイジェスト認証メカニズム、あるいはより強いものを使用したいと思う人がいるかもしれない。

10 仕様

この仕様書において、"MUST", "MUST NOT", "SHOULD", "SHOULD NOT", "MAY"各キーワードは RFC 2119 [3] に記述されるように解釈される。

10.1 プロトコルパラメータの仕様

この仕様書では新しい HTTP パラメータタイプ、instance-manipulation を定義する:

 instance-manipulation = token [imparams]

 imparams = ";" imparam-name [ "=" ( token | quoted-string ) ]
 imparam-name = token

imparam-name は、qvalues ([10] 参照) の使用との曖昧さを避けるために、"q" としてはならない 事に注意せよ。

instance-manipulation 値の初期のセットとして:

vcdiff
"vcdiff" エンコーディングフォーマット [19, 20] を使用した差分。
diffe
UNIX "diff -e" コマンド [26] の出力。
gdiff
GDIFF エンコーディングフォーマット [14]
gzip
HTTP "gzip" 内容コーディングと同じ定義。
deflate
HTTP "deflate" 内容コーディングと同じ定義。
range
その結果が範囲選択の結果としての、部分的内容であるという事を示すトークン。
identity
A-IM ヘッダ (IM ヘッダではない) 中のみで使用されるトークンで、identity インスタンス操作が利用可能かどうかを示すためのものである。

この仕様書の以下を簡便にするために、delta-coding 値として、instance-manipulation 値の部分集合を定義する。

delta-coding = "vcdiff" | "diffe" | "gdiff" | token

将来の instance-manipulation 値もまたこのリスト中に含まれるかもしれない。

10.2 IANA について

Internet Assigned Numbers Authority (IANA) は、instance-manipulation 値についての名前空間を管理する。 値とその意味は、独立した実装間での相互運用が可能なように、RFC あるいは他のよく検討された{peer-reviewed}、永続的で容易に利用可能な参照の中で、詳細に文書化されなければならない。 このような制約に従うので、名前の割り当ては早い者勝ちである (RFC 2434 [25] 参照)。

この仕様では、更に IANA HTTP ステータスコードレジストリに新しい値を加える (RFC 2817 [18] 参照)。 このコードの仕様については section 10.4.1 を参照。

10.3 差分エンコードされたレスポンスの基本要件

サーバは、以下の条件の全てが真である場合、差分エンコードされたレスポンスを送る事ができる:

  1. サーバは、そのリクエストのために 200 (OK) レスポンスを送る事ができる。
  2. そのクライアントのリクエストは、少なくとも一つ delta-coding を列挙する A-IM ヘッダフィールドを含んでいる。
  3. そのクライアントのリクエストは、リクエストURI のインスタンス("基点インスタンス") のための少なくとも一つの妥当なエンティティタグを列挙する If-None-Match ヘッダフィールドを含んでいる。

差分エンコードされたレスポンスは:

10.4 ステータスコードの仕様

以下の新しいステータスコードを HTTP のために定義する。

10.4.1 226 IM Used

サーバはそのリソースに対する GET リクエストを実行し、そのレスポンスは現在のインスタンスに適用された一つ以上のインスタンス操作の結果の表現である。 実際の現在のインスタンスは、特定のインスタンス操作に対して適切なように、このレスポンスを他の以前のあるいは以後のレスポンスと組み合わせる場合以外は利用可能ではないかもしれない。 その場合、生成されたインスタンスのヘッダは、HTTP/1.1 仕様書 [10] の section 13.5.3 の規則に従って、ステータス 226 レスポンスのものと他のインスタンスからのものを組み合わせたヘッダとなる。

リクエストは、少なくとも一つの instance-manipulation を列挙した A-IM ヘッダフィールドを含んでいなければならない。 レスポンスは、現在のインスタンスのエンティティタグを与える Etag ヘッダフィールドを含んでいなければならない

226 のステータスコードと共に受信されたレスポンスは、HTTP 期限メカニズム、任意の Cache-Control ヘッダ、及び section 10.6 の条件に従って、キャッシュによって保存され、以降のリクエストへの応答として使用する事ができる

226 のステータスコードと共に受信されたレスポンスは、現在のインスタンスのためのキャッシュエントリを作るために、基点インスタンスのためのキャッシュエントリと組み合わせて、キャッシュによって保存する事ができる

10.5 ヘッダの仕様

以下のヘッダは、エンティティヘッダとしての使用されるために、定義される。 (section 3 にて議論された用語による混乱により、いくつかのエンティティヘッダは、エンティティよりもむしろインスタンスに関連している。 )

10.5.1 Delta-Base

Delta-Base エンティティヘッダフィールドは、基点インスタンスのエンティティタグを指定するために、差分エンコードされたレスポンス中で使用される。

 Delta-Base = "Delta-Base" ":" entity-tag

Delta-Base ヘッダフィールドは、リクエストがその If-None-Match ヘッダフィールドに一つ以上のエンティティタグを含んでいた場合、delta-codingを含んでいる IM ヘッダを持つレスポンスに含まれなければならない

delta-coding を含んでいる IM ヘッダを持つ任意のレスポンスは、Delta-Base ヘッダを含む事ができる。

我々は、他にどんな差分エンコードされたレスポンスが Delta-Base ヘッダを含まなければならない か、あるいは含むべきである かについてはわからないが、網羅的あるいは形式的な分析はなされていない。 実装者は、全ての差分エンコードされたレスポンス中に Delta-Base ヘッダを含むのが賢いかもしれない。

Delta-base ヘッダが無い差分エンコードされたレスポンスを受け取るキャッシュやプロクシは、その値がリクエストの If-None-Match フィールドにて与えられるエンティティタグ (但しそのフィールドに列挙されるエンティティタグがただ一つである場合のみ) であるような Delta-base ヘッダを加える事ができる

10.5.2 IM

IM レスポンスヘッダフィールドがある場合、それはレスポンスによって表わされるインスタンスに適用された instance-manipulation を示すために使用される。 典型的なインスタンス操作は差分エンコーディングや圧縮を含む。

 IM = "IM" ":" #(instance-manipulation)

instance-manipulation は section 10.1 にて定義される。

特別な場合として、instance-manipulation に、範囲選択と少なくとも一つidentity 以外の instance-manipulation の両方を含んでいる場合、IM ヘッダフィールドは、範囲選択を含む、それら全ての instance-manipulation が適用された順序を示すために使用されなければならない。 IM ヘッダが"range" という instance-manipulation を列挙する場合、レスポンスはContent-Range ヘッダか、それぞれの部分に Content-Range ヘッダを持つmultipart/byteranges の Content-Type のいずれかを含まなければならない。 (差分エンコーディングと multipart/byteranges を組み合わせるという特定の場合の議論については section 10.10 参照。 )

IM ヘッダを含むレスポンスは、section 10.4.1 にて明示されるように、226 (IM Used) のレスポンスステータスコードを転送しなければならない

サーバは、IM ヘッダが "range" という instance-manipulation のみを示していた場合、それを省略すべきである。 そのようなレスポンスは、HTTP/1.1 [10] にて明示されるように、通常レスポンスステータスコード 206 (Partial Content) をもって送られるであろう。

IM ヘッダの使用例は以下のものを含んでいる:

 IM: vcdiff

この例は、このエンティティボディは、vcdiff エンコーディングを使用して、インスタンスの差分エンコーディングであるという事を示す。

 IM: diffe, deflate, range

この例は、インスタンスが初めに diffe エンコーディングを使用して差分エンコードされ、次にその結果を deflate を使用して圧縮し、最後にその圧縮したエンコーディングの一つ以上の範囲が選択されたという事を示す。

 IM: range, vcdiff

この例は、インスタンスの一つ以上の範囲が選択され、その結果は以前の基点インスタンスの圧縮前の範囲に対して差分エンコードされたという事を示す。

以降のリクエストへ応答するためにあるリクエストへの応答を受信するレスポンスを使用するキャッシュは、キャッシュされたレスポンスが IM ヘッダフィールドを含む場合、section 10.6 の規則に従わなければならない。

10.5.3 A-IM

A-IM リクエストヘッダフィールドは Accept に似ているが、レスポンス中に受け入れ可能な instance-manipulation (section 10.1) を制限する。 section 10.5.2 にて明示されるように、レスポンスは複数の instance-manipulation を適用した結果であるかもしれない。

 A-IM = "A-IM" ":" #( instance-manipulation
                          [ ";" "q" "=" qvalue ] )

A-IM リクエストヘッダフィールドが一つ以上の delta-coding 値を含んでいる時、リクエストはそのリクエストURI についての以前のレスポンスからの一つ以上のエンティティタグを列挙する、If-None-Match ヘッダフィールドを含まなければならない

サーバは、与えられた A-IM ヘッダフィールドによって、(それが使用する事が可能なものの中で) instance-manipulation が受け入れ可能かどうかを、以下の規則を使用して、試す:

  1. instance-manipulation が A-IM フィールド中に列挙される場合、それが 0 の qvalue を伴っていなければ、受け入れ可能である。 (HTTP/1.1 仕様書 [10] の section 3.9 にて定義されるように、0 の qvalue は "利用不可能" を意味する。 ) もしリクエスト中の A-IM ヘッダにて instance-manipulation が列挙されなければ、サーバはレスポンスに identity ではない instance-manipulation を使用してはならない
  2. 複数の非互換的 instance-manipulation が受け入れ可能である場合、最も高い 0 でない qvalue を持つ instance-manipulation が望まれる。
  3. A-IM フィールドに "identity;q=0" を含む事により特に拒否されるのでなければ、"identity" という instance-manipulation は常に受け入れ可能である。

A-IM フィールドがリクエスト中にあり、サーバがその A-IM ヘッダによって受け入れ可能であるとするようなレスポンスを送る事ができない場合、サーバは 406 (Not Acceptable) ステータスコードのエラーレスポンスを送るべきである

レスポンスが複数の instance-manipulation を使用する場合、そのinstance-manipulation は A-IM リクエストヘッダフィールド中に現われる順に適用されなければならない

サーバが instance-manipulation を適用するかどうかについての選択は、そのレスポンスに以降のあらゆる two-input instance-manipulation を適用するための選択とは独立であるべきである。 (two-input instance-manipulation は、入力として二つの異なる値をとるので、delta-codings を含む。 圧縮や "range" という instance-manipulation は一つの入力のみをとる。 他の instance-manipulation は将来定義されるかもしれない。 )

注: この要求の意図は、クライアントが最初に自身のキャッシュされた基点インスタンスへ instance-manipulation のエンコーディングを適用した場合にのみデコードできるような差分エンコードされたレスポンスをサーバが生成するのを防ぐ事にある。 サーバ実装者は、delta-coding の前にどの instance-manipulation を適用するかを決める時に、クライアントが自身のキャッシュに論理上何を持っているかを考慮したいと思うかもしれない。

例:

 A-IM: vcdiff, gdiff

この例は、クライアントは vcdiff か gdiff フォーマットの差分エンコーディングを受け入れる事ができるという事を意味する。

 A-IM: vcdiff, gdiff;q=0.3

この例は、クライアントは vcdiff か gdiff フォーマットの差分エンコーディングを受け入れる事ができるが、vcdiff フォーマットをより望むという事を意味する。

 A-IM: vcdiff, diffe, gzip

この例は、クライアントは vcdiff か gdiff フォーマットの差分エンコーディングを受け入れる事ができ、また gzip で圧縮される差分エンコーディング出力を受け入れる事ができるという事を意味する。 また、A-IM では diffeが使用される場合のみ gzip が使用されていると主張する方法は提供されていないので、クライアントは、差分エンコーディングがなされていない、インスタンスの gzip 圧縮を受け入れる事ができるという事も意味する。

受け入れ可能な instance-manipulation の有用な組み合わせを選ぶ事は、サーバ実装者に委ねられる (例えば、diffe を gzip するのは有用だが、vcdiff を gzip するのは恐らく有用ではない)。

10.6 226 レスポンスについてのキャッシングの規則

クライアントやプロクシが 226 (IM Used) レスポンスを受信した場合、以下の三つの方法でキャッシュエントリを作るためにこのレスポンスを使用する事ができる:

  1. 元のインスタンスを得るために全ての instance-manipulation をデコードし、キャッシュ中にそのインスタンスを保存する事ができる。 この場合、得られたインスタンスはステータス 200 レスポンスとして保存され、通常の HTTP キャッシングについての規則に従って使用されなければならない

  2. 範囲選択を除く全ての instance-manipulation をデコードし、キャッシュ中にその結果を保存する事ができる。 この場合、その結果はステータス 206 レスポンスとして保存され、部分的内容についての通常の HTTP キャッシングについての規則に従って使用されなければならない

  3. キャッシュエントリとしてステータス 226 (IM Used) レスポンスを保存する事ができる

ステータス 226 のキャッシュエントリは、以下のいずれかの条件の下ではそれ以降のリクエストへのレスポンスには使用されてはならない (ステータス 226 レスポンスを保存しないキャッシュはこれらの検証を無視してよい):

  1. キャッシュされたレスポンス中の IM ヘッダフィールドからの任意のinstance-manipulation 値が、以降のリクエストの A-IM ヘッダフィールド中に現れない場合。 ヘッダ間の比較は、あらゆる関連したimparams 値を含む各 instance-manipulation 上で正確なマッチを使用してなされる (section 10.1 参照)。

  2. キャッシュされた IM ヘッダフィールド中に現われる instance-manipulation 値の順序が、以降のリクエストの A-IM ヘッダフィールドでの instance-manipulation のセットの順序と異なる場合。

  3. キャッシュ実装が、キャッシュされた IM ヘッダフィールド中の任意の instance-manipulation 値の仕様について、知らない、あるいは少なくとも条件付きで従順でないような場合。

    注: この規則によって、展開されているキャッシュ実装にエラーをもたらす事無く、instance-manipulation のセットを拡張する事ができるようにする。 新たな instance-manipulation の仕様では、認識する実装中のキャッシュヒット率を改善するために追加的キャッシング規則を含んでいてもよい。

  4. キャッシュされた IM ヘッダフィールド中の instance-manipulation値のいずれかが delta-coding であり、そのキャッシュエントリがDelta-Base ヘッダフィールドを含んでおり、かつ Delta-Base エンティティタグが以降のリクエストの If-None-Match ヘッダフィールド中に列挙されるエンティティタグの一つではない場合。

  5. キャッシュされた IM ヘッダフィールド中の instance-manipulation値のいずれかが delta-coding であり、そのキャッシュエントリがDelta-Base ヘッダフィールドを含んでおらず、かつそのキャッシュエントリに通じるリクエストの If-None-Match ヘッダフィールドが以降のリクエストの If-None-Match ヘッダフィールドに一致しないない場合。

キャッシュされたレスポンスの IM ヘッダフィールドが "range" というinstance-manipulation を含む場合、ステータス 226 のキャッシュエントリは、キャッシュされた 206 (Partical Content) レスポンスにおける場合でのように、キャッシュされたレスポンスがリクエスト中の Range ヘッダフィールドの値と一致しない場合、以降のリクエストへのレスポンスに使用されてはならない

注: 我々は、キャッシュされたステータス 206 レスポンスが以降のリクエストと一致しているかどうかを決定するための公に発行された仕様書の存在を知らない。 以下の条件のどちらかでそれを満たすと考える:

  1. キャッシュされたレスポンスに結びついたリクエストのヘッダ中で指定された範囲は、以降のリクエストのヘッダ中で指定される物と同じである。

  2. キャッシュされたレスポンスで指定された範囲は、以降のリクエストのヘッダ中で指定される物と同じである。

更なる分析が必要かもしれない。

10.7 内容コーディングがある時の差分の規則

内容コーディングされたインスタンスへの差分エンコーディングの使用は、いくらか複雑さを増す事となる。 クライアント (恐らくプロクシ) が差分エンコードされたレスポンスを受信した場合、新しいレスポンスとキャッシュされる以前のレスポンスのいずれかあるいは両方は、identity 以外の content-coding を持っているかもしれない。 我々は、クライアントがサーバのレスポンスの意味を理解できないような状況を防ぐために、サーバとクライアントのための規則を明示する。

10.7.1 内容コーディングがある時の差分の生成の規則

サーバが差分エンコードされたレスポンスを生成する場合、サーバが使用する内容コーディングの値 (すなわち、レスポンスの Content-Encoding ヘッダフィールドの値) は、差分エンコーディングを生成していないサーバが使用していた内容コーディングのリストの接頭辞であるべきである

この条件によって、差分エンコードされたレスポンスを受信するクライアントがプロセス間で内容コーディングを適用する必要なしにキャッシュされた基点インスタンスに差分を適用する事を可能にする (もちろん、クライアントはいくらか解読する事を要求されるかもしれないが)。

10.7.2 内容コーディングがある時の差分の適用の規則

クライアントが一つ以上の identity でない内容コーディングがなされた差分レスポンスを受信する時:

  1. 新たな (差分) レスポンスとキャッシュされたレスポンス (インスタンス) の両方が全く同じ内容コーディングのセットを持っているならば、クライアントは一方のレスポンスから内容コーディングを取り除く事なくキャッシュされたレスポンスに差分レスポンスを適用する。
  2. 新たな (差分) レスポンスとキャッシュされたレスポンス (インスタンス) が異なる内容コーディングのセットを持っているならば、クライアントは差分を適用する前に、その結果が差分レスポンスと同じ内容コーディングのセットとなるまで、キャッシュされたレスポンスから一つ以上の内容コーディングをデコードする。
  3. プロクシやキャッシュがキャッシュされた基点インスタンスのレスポンスへ差分レスポンスを適用した結果を転送する、あるいはキャッシュエントリからこの結果を後に転送するならば、転送されたレスポンスは新たな (差分) レスポンスと同じ Content-Encoding ヘッダフィールドを転送しなければならない (そしてそれはそのヘッダフィールドによって示されるように内容エンコードされていなければならない)。

これらの規則 (特に規則 #3) の意図は、その結果が常に、エンティティタグが内容コーディングの結果に関係している、そして差分エンコードの適用の後のあらゆる受信者はそれがオリジンサーバからのステータス 200 レスポンスとして受け取ったのと全く同じ (あらゆる差分エンコーディングなしの)レスポンスを受信するという規則に一致しているという事である。

10.7.3 A-IM, IM, content-coding の使用例

キャッシュが空であるクライアントが以下のリクエストを送信したと仮定する:

 GET /foo.html HTTP/1.1
 Host: example.com
 Accept-encoding: gzip

そしてオリジンサーバは以下のレスポンスを返す:

 HTTP/1.1 200 OK
 Date: Wed, 24 Dec 1997 14:00:00 GMT
 Etag: "abc"
 Content-encoding: gzip

ここで、特定のインスタンスを意味するために記法 URI;エンティティを使用すると、このレスポンスはクライアントに自身のキャッシュにそのエンティティ GZIP(foo.html; "abc") を保存させるであろう。

そして、数分後、以下の条件付リクエストを発行したと仮定する:

 GET /foo.html HTTP/1.1
 Host: example.com
 If-none-match: "abc"
 Accept-encoding: gzip
 A-IM: vcdiff

サーバが差分エンコードされたレスポンスを生成できるならば、いくつかの選択肢があるだろう。 一つ目は、(これは最も効果的なコーディングを強制できないが) 圧縮されたインスタンスから差分を計算する事である。

 HTTP/1.1 226 IM Used
 Date: Wed, 24 Dec 1997 14:01:00 GMT
 Etag: "def"
 Delta-base: "abc"
 Content-encoding: gzip
 IM: vcdiff

このレスポンスのボディは、VCDIFF_DELTA(GZIP(foo.html;"abc"), GZIP(foo.html;"def")) の結果となるであろう。 クライアントは、自身の以前のキャッシュエントリに差分を適用しエンティティを回復した後に、新たなキャッシュエントリとしてエンティティ GZIP(foo.html;"def") を保存するであろう。

サーバの別の選択肢は圧縮されてない値から差分を計算する事であり、以下のものが返された場合:

 HTTP/1.1 226 IM Used
 Date: Wed, 24 Dec 1997 14:01:00 GMT
 Delta-base: "abc"
 Etag: "ghi"
 IM: vcdiff

このレスポンスのボディは、VCDIFF_DELTA(GUNZIP(GZIP(foo.html;"abc")), foo.html;"ghi") か、あるいはより単純な VCDIFF_DELTA(foo.html;"abc",foo.html;"ghi") の結果となるであろう。 クライアントは、自身の以前のキャッシュエントリに差分を適用しエンティティを回復した後に、新たなキャッシュエントリとしてエンティティ foo.html;"ghi" を保存するであろう。

gzip 内容コーディングがなされていない新たな foo.html (14:01:00 GMT 時点) の値は、同じ基本となるファイルの圧縮されたインスタンスからのエンティティタグとは異なるものを持たなければならない。

クライアントの二番目のリクエストは以下のようなものであった:

 GET /foo.html HTTP/1.1
 Host: example.com
 If-none-match: "abc"
 Accept-encoding: gzip
 A-IM: diffe, gzip

クライアントは、サーバが差分エンコードをサポートしていない場合でも、最小限の (内容コーディングによる) 圧縮による利益を受けたいと思い、Accept-Encoding と A-IM の両方で gzip を列挙した。 しかし、サーバが diffe 差分コーディングをサポートしていれば、そちらで圧縮される事を望み、これはインスタンス操作としてなされなければならない。

diffe をサポートするサーバは、以下の通り応答する:

 HTTP/1.1 226 IM Used
 Date: Wed, 24 Dec 1997 14:01:00 GMT
 Delta-base: "abc"
 Etag: "ghi"
 IM: diffe, gzip

このレスポンスのボディは、GZIP(DIFFE_DELTA(GUNZIP(GZIP(foo.html;"abc")), foo.html;"ghi")) か、あるいはより単純な GZIP(DIFFE_DELTA(foo.html;"abc", foo.html;"ghi"))の結果となるであろう。 この場合、gzip 圧縮はインスタンス操作であり、内容コーディングではないので、再結合されたレスポンスが保存されたり転送される時もそれは保持されず、クライアントは新たなキャッシュエントリとして (任意の内容コーディングや圧縮なしに) エンティティ foo.html;"ghi"を保存するであろう。

10.8 新たな Cache-Control 指示子

我々は二つの新たな cache-directives を定義する (cache-directive の仕様については RFC 2616 [10] の section 14.9 を参照)。

10.8.1 retain 指示子

retain 指示子を含むために、cache-response-directive の値のセットを拡張する。

 cache-response-directive = ...
         | "retain" [ "=" delta-seconds ]

retain 指示子は常にサーバからクライアントへの "ヒント" である; すなわち、受信者への強制的動作を明示するものではない。

retain 指示子がある事によって、差分に対応するクライアントは自身のキャッシュのそのレスポンスに、空間が許せば、インスタンスを保持すべきであり、また差分エンコードされたレスポンスへの将来のリクエスト中では対応するエンティティタグを使用すべきであるという事を示す。 すなわち、サーバはおそらく基点インスタンスとして対応するインスタンスを使用して差分エンコードされたレスポンスを提供するであろう。 暗黙的に、クライアントが、"retain" と印付けられるものと、そうでないような、リソースのインスタンスが取得されキャッシュされる場合、"retain" と印付けられないインスタンスをキャッシュする事には意味がない。

retain 指示子が delta-seconds 値を含む場合、サーバはおそらく指定された秒数の後に基点インスタンスとして対応するインスタンスの使用をやめるであろう。 クライアントは、その期間が過ぎた後に差分エンコードされたレスポンスのための対応するエンティティタグを使用すべきでない。 その期間はレスポンスが生成されてから測られるので、クライアントはその計算にレスポンスの Age を含むべきである。

retain 指示子が 0 の delta-seconds 値を含む場合、クライアントは差分エンコードされたレスポンスのための将来のリクエスト中で対応するエンティティタグを使用すべきではない

注: 我々は、サーバ実装者がそれを利用する能力を持ってはならないクライアントやプロクシに "retain=0" 指示子を送る事で、暗黙的に帯域幅を考慮する事を推奨する。

10.8.2 im 指示子

im 指示子を含むために、cache-response-directive の値のセットを拡張する。

 cache-response-directive = ...
         | "im"

IM ヘッダ、A-IM ヘッダ、及び 226 レスポンスステータスコードの仕様に従うキャッシュは、同じレスポンス中に im 指示子が存在する時は、no-storecache-directive を無視すべきである。 その他の全ての実装は、im 指示子を無視しなければならない (すなわち、im 指示子があれば、no-store 指示子に気付かなければならない)。

10.9 差分エンコーディングと合わせての圧縮の使用

diffe や gdiff 差分コーディングによるデータ圧縮の適用は、多くの場合、その結果のメッセージボディのサイズの大きな減少を見せている。 (一方、vcdiff コーディングは本来圧縮機能が備わっており、更なる圧縮による利益はない。) 従って、diffe や gdiff 差分コーディングをサポートする実装はgzip や deflate 圧縮コーディングも実装する事を強く推奨する。 (deflateコーディングはより小さな結果を提供する。) しかし、これは、圧縮や展開に関する CPU-time コストが高くつく環境もあるだろうから、差分エンコーディングの使用のための最優先要件ではない。

インスタンス操作として差分エンコーディングと圧縮の両方をサポートするクライアントは、例えば、以下のようにして知らせる。

 A-IM: diffe, deflate

サーバがレスポンスに両方のインスタンス操作を使用した場合、圧縮は差分エンコーディングの結果に適用されるという section 10.5.3 にて述べられた順序の規則が適用され、その逆とはならない。 すなわち、この場合のレスポンスは以下のものを含むだろう。

 IM: diffe, deflate

クライアントは内容コーディングとしてもインスタンス操作としても圧縮を受け入れるであろうという事に注意せよ。 例えば:

 Accept-Encoding: gzip
 A-IM: gzip, gdiff

この例では、サーバは差分エンコーディングの前に、内容コーディングあるいはインスタンス操作として、gzip 圧縮を適用するであろう。 エンティティタグは内容コーディングの後だがインスタンス操作の前に割り当てられるので、この選択は差分コーディングの意味論{semantics} に影響がある事を覚えておく必要がある。

差分エンコーディングと multipart/byteranges

クライアントは、単一のリクエストで、複数の隣接しないバイト範囲を要求する事ができる。 サーバのレスポンスは、レスポンス中で複数の範囲を転送するために "multipart/byteranges" メディアタイプ ([10] の section 19.2) を使用する。 multipart/byteranges レスポンスが差分エンコードされる (すなわち、インスタンス操作として delta-coding を使用する) 場合、差分に関連するヘッダは個々の部分ではなく、レスポンス全体に関連している。 (これは、一つの基点インスタンスと、一つの現在の含まれるインスタンスがあるのみだからである。) 複数の範囲を持つ差分エンコードされたレスポンスは、全ての範囲において同じ delta-coding を使用しなければならない

サーバが multipart/byteranges レスポンスのために差分エンコーディングを使用する事を選択したる場合、以下の規則に従ってレスポンスを生成しなければならない

multipart/byteranges レスポンスが範囲選択より先に delta-coding を使用する場合、A-IM と IM ヘッダフィールドは "range" リテラルの前に delta-coding を列挙する。 (これはメッセージ送信の未完異常終了の後に部分的レスポンスを得るためにとられるアプローチである事を思い出せ。 ) サーバは最初に、基点インスタンスと現在のインスタンス間の違い (差分) を表わすバイトのシーケンスを生成し、次に指定されたバイトの範囲を選択し、multipart/byteranges メディアタイプの部分中にてそれぞれの範囲を送信する。

multipart/byteranges レスポンスが範囲選択の後に delta-coding を使用する場合、A-IM と IM ヘッダフィールドは "range" リテラルの後に delta-coding を列挙する。 (これはちょうどインスタンスの選択部分の更新されたバージョンを得るためにとられるアプローチである事を思い出せ。 ) サーバは最初に、現在のインスタンスから指定された範囲を選択し、また基点インスタンスからも同じ範囲を選択する。 (インスタンスが長すぎない場合は、選択された範囲のうちのいくつかは空のシーケンスかもしれない。 ) その後サーバは、一組の範囲間の違い (差分) を生成し、multipart/byteranges メディアタイプの部分中にてそれぞれの違いを送信する。

11 プロトコルによる負荷の定量化

提案されたプロトコルの変更は、HTTP メッセージヘッダのサイズをわずかに増加させる。 最も単純な場合では、条件付リクエスト (すなわち、クライアントが既にキャッシュエントリに持っているような URI のためのもの) は、もう一つ多くヘッダを含むであろう、例えば:

 A-IM:vcdiff

これはおよそ 13 バイトの増加である。 最近の研究 [23] では、281 と 306バイトの二つの異なる記録からリクエストサイズの平均値を報告しているので、リクエストサイズの正味の増加量は 4% から 5% の間であろう。

クライアントは差分エンコードされたレスポンスのための基点として使用するために既存のキャッシュエントリを持っていなければならないので、その無条件のリクエストにおいては "A-IM: vcdiff" を (あるいは、他の差分エンコーディングを列挙して) 送ってはならない。 同じ研究では、長く記録された中のリクエストの少なくとも 46% はその記録にて以前に見られなかったURL についてあったという事を示した; すなわち、これは典型的なクライアントリクエストの約半分のみが条件付きであろう (また、本来のキャッシュには有限のサイズが与えられており、実際の割合はおそらくこれより小さいであろう) という事を意味する。

その研究では更に、長く記録された中のレスポンスの 64% が画像内容タイプ (GIF と JPEG) のためにあったという事を示した。 section 6 にて注目されるように、我々は現在、そのような画像タイプに適した差分エンコーディングフォーマットを知らない。 もしクライアントがそのような差分エンコーディングフォーマットをサポートしていなければ、画像内容タイプに条件付リクエストを行う時、推測上差分を求めないであろう。

これらの要因から合わせて得られる所から、リクエストヘッダサイズの平均増加量は、5% よりずっと小さく、恐らく 1% 未満であるだろうという事を示唆する。

差分エンコードされたレスポンスはわずかに長いヘッダを転送する。 最も単純な場合では、レスポンスがもう一つ多くヘッダを転送する、例えば:

 IM:vcdiff

これは約 11 バイトである。 ("Delta-Base" のような) 他のヘッダも含まれているかもしれない。 しかし、差分エンコーディングが現実に使用される場合以外においては、どんなこれらの追加的ヘッダも含まれないであろうし、これが正味のレスポンスサイズを増加させるのであれば、レスポンスの送信者は差分エンコーディングを送る事を避ける事ができる。 従って、差分エンコードされたレスポンスは、同じリクエストにおける正規のレスポンスより大きくあってはならない。

シミュレーションでは、ともかく差分エンコーディングが上手くいった場合には、それが数千バイトを節約するという事を示す。 従って、レスポンスヘッダに何ダースかのバイト数を加えても、メッセージボディサイズ中の節約されたものを打ち消すような事にはほとんどならない。

最後に、"retain" Cache-Control 指示子の使用は、ある追加的オーバーヘッドを引き起こすかもしれない。 あるサーバヒューリスティックスは、それらが恐らく将来のレスポンスを最適化するような状況に、これらのヘッダの使用を制限する事に成功するかもしれない。 これらのヘッダのどちらも、差分エンコーディングのより単純な用途には必要ではない。

12 セキュリティに関する考察

我々は、HTTP/1.1 プロトコルについて既存のセキュリティに関する考察に影響するような基本的な差分エンコーディングメカニズムのどんな側面にも気づいていない。

13 謝辞

Phong Vo は、差分エンコーディングのアルゴリズムとフォーマットにおいて非常に多くの指導を提供した。 Issac Goldstand と Mike Dahlin は、仕様上の多くの有用なコメントを提供した。 Dave Kristol は、多くの原文の修正を示唆した。

14 知的所有権

IETF は、この文書に含まれる仕様の一部あるいは全てに関して要求される知的所有権について通知を受けている。 要求される権利のオンラインリストをより詳しく調べるためには、<http://www.ietf.org/ipr.html> 参照。

IETF は、この文書に記述される技術の実装や使用に付随すると主張されるかもしれない知的財産や他の権利の正当性や範囲について、あるいはこのような権利の元でそのライセンスが利用可能か利用不可能かの範囲についてどんな立場もとらない; また、この様な権利を認識するためのどんな努力も行ったとも表明しない。 IETF の standards-track とこれに関連する文書中の権利に関しての手続きの情報は BCP 11 にて見る事ができる。 出版において利用可能であるという権利や利用可能であるとされるあらゆるライセンスの保証の主張のコピーや、この仕様の実装者や利用者によってそのような所有権の使用について一般的なライセンスや許可を得ようとする試みの結果は、IETF 事務局にて得る事ができるであろう。

15 参照文献

1
Gaurav Banga, Fred Douglis, and Michael Rabinovich. Optimistic Deltas for WWW Latency Reduction. Proc. 1997 USENIX Technical Conference, Anaheim, CA, January, 1997, pp. 289-303.
2
Berners-Lee, T., Fielding, R. and H. Frystyk, Hypertext Transfer Protocol -- HTTP/1.0, RFC 1945, May 1996.
3
Bradner, S., Key words for use in RFCs to Indicate Requirement Levels, BCP 14, RFC 2119, March 1997.
4
Edith Cohen, Balachander Krishnamurthy, and Jennifer Rexford. Improving End-to-End Performance of the Web Using Server Volumes and Proxy Filters. Proc. SIGCOMM '98, September, 1998, pp. 241-253.
5
Deutsch, P., GZIP file format specification version 4.3, RFC 1952, May 1996.
6
Deutsch, P., DEFLATE Compressed Data Format Specification version 1.3, RFC 1951, May 1996.
7
Deutsch, P. and J. Gailly, ZLIB Compressed Data Format Specification version 3.3, RFC 1950, May 1996.
8
Fred Douglis, Anja Feldmann, Balachander Krishnamurthy, and Jeffrey Mogul. Rate of Change and Other Metrics: a Live Study of the World Wide Web. Proc. Symposium on Internet Technologies and Systems, USENIX, Monterey, CA, December, 1997, pp. 147-158.
9
Fielding, R., Gettys, J., Mogul, J., Frystyk, H. and T. Berners-Lee, Hypertext Transfer Protocol -- HTTP/1.1, RFC 2068, January 1997.
10
Fielding, R., Gettys, J., Mogul, J., Nielsen, H., Masinter, L., Leach, P. and T. Berners-Lee, Hypertext Transfer Protocol -- HTTP/1.1, RFC 2616, June 1999.
11
Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S., Leach, P., Luotonen, A., Sink, E. and L. Stewart, HTTP Authentication: Basic and Digest Access Authentication, RFC 2617, June 1999.
12
Freed, N. and N. Borenstein, Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies, RFC 2045, November 1996.
13
Arthur van Hoff, John Giannandrea, Mark Hapner, Steve Carter, and Milo Medin. The HTTP Distribution and Replication Protocol. Technical Report NOTE-DRP, World Wide Web Consortium, August, 1997.
14
Arthur van Hoff and Jonathan Payne. Generic Diff Format Specification. Technical Report NOTE-GDIFF, World Wide Web Consortium, August, 1997.
15
Barron C. Housel and David B. Lindquist. WebExpress: A System for Optimizing Web Browsing in a Wireless Environment. Proc. 2nd Annual Intl. Conf. on Mobile Computing and Networking, ACM, Rye, New York, November, 1996, pp. 108-116.
16
James J. Hunt, Kiem-Phong Vo, and Walter F. Tichy. An Empirical Study of Delta Algorithms. IEEE Soft. Config. and Maint. Workshop, 1996.
17
Jacobson, V., Compressing TCP/IP Headers for Low-Speed Serial Links, RFC 1144, February 1990.
18
Khare, R. and S. Lawrence, Upgrading to TLS Within HTTP/1.1, RFC 2817, May 2000.
19
David G. Korn and Kiem-Phong Vo. A Generic Differencing and Compression Data Format. Technical Report HA1630000-021899-02TM, AT&T Labs - Research, February, 1999.
20
Korn, D. and K. Vo, The VCDIFF Generic Differencing and Compression Data Format, Work in Progress.
21
Merriam-Webster. Webster's Seventh New Collegiate Dictionary. G. & C. Merriam Co., Springfield, MA, 1963.
22
Jeffrey C. Mogul. Hinted caching in the Web. Proc. Seventh ACM SIGOPS European Workshop, Connemara, Ireland, September, 1996, pp. 103-108.
23
Jeffrey C. Mogul, Fred Douglis, Anja Feldmann, and Balachander Krishnamurthy. Potential benefits of delta encoding and data compression for HTTP. Research Report 97/4, DECWRL, July, 1997.
24
Mogul, J. and A. Van Hoff, Instance Digests in HTTP, RFC 3230, January 2002.
25
Narten, T. and H. Alvestrand, Guidelines for Writing an IANA Considerations Section in RFCs, BCP 26, RFC 2434, October 1998.
26
The Open Group. The Single UNIX Specification, Version 2 - 6 Vol Set for UNIX 98. Document number T912, The Open Group, February, 1997.
27
W. Tichy. RCS - A System For Version Control. Software - Practice and Experience 15, 7 (July 1985), 637-654.
28
Andrew Tridgell and Paul Mackerras. The rsync algorithm. Technical Report TR-CS-96-05, Department of Computer Science, Australian National University, June, 1996.
29
Stephen Williams. Personal communication. http://ei.cs.vt.edu/~williams/DIFF/prelim.html.
30
Stephen Williams, Marc Abrams, Charles R. Standridge, Ghaleb Abdulla, and Edward A. Fox. Removal Policies in Network Caches for World-Wide Web Documents. Proc. SIGCOMM '96, Stanford, CA, August, 1996, pp. 293-305.

16 筆者のアドレス

 Jeffrey C. Mogul
 Western Research Laboratory
 Compaq Computer Corporation
 250 University Avenue
 Palo Alto, California, 94305, U.S.A.

 Phone: 1 650 617 3304 (email preferred)
 EMail: JeffMogul@acm.org

 Balachander Krishnamurthy
 AT&T Labs - Research
 180 Park Ave, Room D-229
 Florham Park, NJ 07932-0971, U.S.A.

 EMail: bala@research.att.com

 Fred Douglis
 AT&T Labs - Research
 180 Park Ave, Room B-137
 Florham Park, NJ 07932-0971, U.S.A.

 Phone: 1 973 360-8775
 EMail: douglis@research.att.com

 Anja Feldmann
 University of Saarbruecken, Germany,
 Computer Science Department
 Im Stadtwald, Geb. 36.1, Zimmer 310
 D-66123 Saarbruecken, Germany

 EMail: anja@cs.uni-sb.de

 Yaron Y. Goland

 Email: yaron@goland.org

 Arthur van Hoff
 Marimba, Inc.
 440 Clyde Avenue
 Mountain View, CA 94043, U.S.A.

 Phone: 1 650 930 5283
 EMail: avh@marimba.com

 Daniel M. Hellerstein
 Economic Research Service, USDA
 1909 Franwall Ave, Wheaton MD 20902

 Phone: 1 202 694-5613 or 1 301 649-4728
 EMail: danielh@crosslink.net or webmaster@srehttp.org

17 著作権表示全文

Copyright © The Internet Society (2002). All Rights Reserved.

この文章とその翻訳は、複製し他人に配布する事ができ、またその実装についてのコメント、その他の方法を用いた説明、その補助となるような派生的作業はそれらの中に上の著作権表示とこの段落を含む事によって、その全て又は一部を、いかなる制約も受けずに、作成、複製、発表、及び配布する事ができる。 しかしながら、インターネット標準化プロセスにて定義されている著作権のための手続きに従わなければならないような場合の中でインターネット標準を開発するという目的に必要である、あるいは英語以外の言語に翻訳する必要があるという場合を除いて、この文章自体を、その著作権表示や、インターネット学会あるいは他のインターネット団体への参照を削除するような、いかなる変更もできない。

上で認めた制限された許諾は永続的なものであり、インターネット学会及びその継承者や譲渡者によって取り消される事は無い。

この文書とここに含まれた情報は、"そのまま {AS IS}" である事を基に提供され、インターネット学会、及び IETF は、この中の情報の使用が、商用利用及び特定用途においていかなる権利もいかなる暗黙的保障も侵害していないという保障への制限を含め、明示的に又は暗黙的に、全ての保障を放棄する

謝辞

RFC Editer 機構の資金は、現在インターネット学会から提供されている。


#TOP
Copyright © 1999-2008 橋本英彦 (H-Hash), All Rights Reserved.