要約

  • RFC 3229 は条件付き GET を拡張した。クライアントは If-None-Match で保有済みインスタンスを示し、A-IM で実行可能な変換を示し、完全コピーの代わりに 226 と IM の手順を受け取れる。
  • 再構成には三つの身元がある。Delta-Base は古い基底、本文は差分命令、応答 ETag は再構成された現在インスタンスを示す。ETag は差分バイトの識別子ではない。
  • 新ステータスは古いキャッシュへの防壁でもあった。未知ヘッダーを無視するだけなら、差分が完全な資源として保存され得る。226 は意味の断絶を無視しにくい場所へ置いた。

条件付き取得は全額かゼロしか節約できなかった

保存した応答が現在も有効なら、304 Not Modified によって再送を避けられる。少しでも変化すれば、通常は新しい値全体を送り直す。初期のキャッシュ整合性はこの二択だった。

一行の変更でも、変わらない大部分は次の転送費用を減らさない。古いインスタンスは、そのまま使えるか、転送上は役に立たないかのどちらかだった。

2002 年 1 月の RFC 3229 は古いコピーを再構成材料へ変えた。サーバーが旧状態と現状態の差分を計算し、現状態を復元する命令だけを送る。

実装は完全に任意で、余分な往復を増やさず平均応答を小さくし、仕組みを知らない HTTP/1.0、HTTP/1.1 と共存することが目標だった。すべての変更が差分に向くとは想定していない。

差分は圧縮でも範囲でもない

RFC はインスタンスを、選択したバリアントにコンテンツコーディングを適用した後、インスタンス操作と転送コーディングを適用する前に 200 GET が返す値として定義した。

圧縮は古いコピーなしで展開できる。差分は通常、計算に使った特定基底を必要とする。範囲は一つの現インスタンスから座標を選ぶ。差分は二つのインスタンス間の変化を記す。

226 は PATCH でもない。GET への応答として、受信側が現在表現を復元するために用いられ、資源の変更を要求しない。RFC 3229 が規定した対象は GET 応答である。

バイト数が減るという共通点だけでは、これらの来歴を交換可能にはできない。

クライアントは出発点を申告する

If-None-Match は手元にある過去インスタンスの ETag を列挙する。A-IM は適用できる操作を列挙する。

そのタグがまだ現在なら 304 でよい。変化していれば、対応サーバーは提示された基底を選び、互換差分を計算できる。基底がない、方式を知らない、費用が合わない場合は 200 を返せる。

これは命令ではなく能力の提示である。クライアントは保有基底と復号形式を管理し、オリジンは履歴保持、計算、基底選択、完全応答へのフォールバックを管理する。

「何との差か」と「どう適用するか」が一致するまで、差分は共有可能な情報にならない。

一応答に三つの対象が存在する

基底インスタンスは既にキャッシュにある。226 本文は変換命令である。命令を適用した出力が現在インスタンスになる。

複数 ETag が提示された場合、Delta-Base が採用基底を指定する。226 の ETag は出力を識別する。RFC は、差分自体はインスタンスではないので、その ETag を差分値へ関連付ける意味はないと明記する。

したがって本文は正しくても単独では使えないことがある。正確な基底、操作、出力身元がそろって初めて意味を持つ。

Content-Length も差分本文の長さであって、再構成した現インスタンスの長さではない。ここを混同すれば、節約された応答が切断された資源に見える。

操作順序も来歴の一部である

処理系列は、資源とバリアントの選択、コンテンツコーディング、インスタンス ETag の割当て、差分や範囲の操作、転送コーディングの順になる。

順序は交換できない。差分後の範囲選択と、範囲選択後の差分は同じとは限らない。圧縮がコンテンツコーディングならインスタンス身元に含まれ、後段の操作なら別の層になる。

A-IM と IM は操作名だけでなく順番を保存する。キャッシュは名前の集合だけを覚え、再利用時に並べ替えてはならない。基底、方式、引数、順序が一つのレシピを成す。

小さい本文を表現へ戻す説明も、節約の成立条件である。

新しい 2xx が古いキャッシュを止めた

設計者は当初、新ステータス追加に消極的だった。必要性は既存中継装置の振る舞いから生じた。

HTTP では未知ヘッダーを無視する。古いプロキシーが IM を無視し、差分本文を保存し、後に完全資源として非対応クライアントへ渡す可能性があった。拡張互換性が静かな破損を生む逆説である。

未知の 226 は、より目立つ安全境界になった。RFC によれば既存プロキシーは未知ステータスを転送しても、キャッシュしないように見えた。理解せず運ぶことはできても、200 として保存しにくい。

Vary: If-None-Match, A-IM だけでは誤検証を防げない場面も明記された。意味の違いを、旧実装が消しにくい位置へ表す必要があった。

IM が手順を示し、226 が完全性の仮定を止める

差分応答は 226 と、少なくとも使用した差分方式を記す IM を必須とする。要求側は A-IM で操作を受け入れ、If-None-Match で基底を提供していなければならない。

226 は、一つ以上のインスタンス操作によって GET が満たされたことを示す。操作によっては、現インスタンスは過去または将来の応答と組み合わせた後にしか得られない。

従って 226 は差分だけの別名ではない。範囲など複数操作を組み合わせる枠組みでもある。IM が有序手順を記し、226 が本文を完全インスタンスと即断させない。

短い理由句より構造化フィールドの方が、再構成には重要である。

能力のあるキャッシュは 200 へ復元できる

保存を全面禁止すれば利点が失われる。仕様は非対応キャッシュと契約全体を理解するキャッシュを分けた。

対応キャッシュは全操作を解いて現在インスタンスを復元し、通常の 200 として保存できる。範囲だけ残して 206 として保存することも、生の 226 を特別規則下で保持することもできる。

生の 226 の再利用には、後の要求が同じ操作、引数、順序を受け入れることに加え、鮮度、基底、身元の条件が必要である。差分は保存しただけで独立バリアントにはならない。

Cache-Control の im 指令は能力境界を作る。普通のキャッシュには no-store が効き、226 と A-IM、IM を理解する実装だけが専用指令を扱う。

過去を残す費用もある

基底が残って初めて差分を使える。クライアントは複数の旧インスタンスを保持して ETag を提示できる。サーバーも履歴を持てば、適切な基底を選び Delta-Base で示せる。

しかしキャッシュ容量、サーバー履歴、CPU、メモリー、I/O は有限である。候補ごとの比較は無料ではなく、保持のヒントも永続保存の約束ではない。

この最適化は保存の動機を変える。直接表示しない古いコピーでも、将来の基底として価値を持つ。オリジンは将来の節約が費用を上回る場合だけ履歴や事前計算を維持すべきである。

200 へ戻る裁量は安全設計の一部だ。差分が大きい、遅い、存在しないなら、完全応答の方が正しい。

現行レジストリーは語彙を保持する

IANA HTTP ステータスコードレジストリー は 226 IM Used を RFC 3229 に登録している。IANA HTTP フィールド名レジストリー は A-IM、Delta-Base、IM を恒久フィールドとして載せる。

登録は普及率を示さない。記号と契約の対応を維持し、別の増分方式が同じ名前を異なる意味へ転用するのを防ぐ。

歴史的な要点は、差分が Web を支配したことではない。少ない転送を正しい結果へ変えるために、HTTP がどれだけ多くの身元を保存しなければならなかったかである。

コピーは再構成後に現れた

226 では、ネットワーク上のメッセージと現表現が同一でなくてよい。転送されるのは変換であり、変換そのものを結果とは呼ばない。

クライアントが基底を証明し、サーバーが選び、IM が操作順を固定し、応答 ETag が出力を識別する。キャッシュは全鎖を理解するか、操作済みバイトを完全文書へ変換するのを諦める。

来歴を失った差分は効率的な真実ではなく、見えない前提を背負った短いバイト列である。

HTTP 226 はその前提を表面へ出した。受信者が得るのは新コピーそのものではなく、自分が保有を証明できる旧コピーから新コピーを作る、検証可能な方法だった。