要約

  • RFC 2068のHTTPバージョンは、送信者のメッセージ形式と将来の通信を理解できる能力を示し、現在のメッセージで使った機能を列挙するものではなかった。
  • プロキシが解釈して次のメッセージを作ると、そのプロキシが新しい送信者になる。上流のバージョンをそのまま能力証明として借りることはできない。
  • 高いマイナーバージョンから古い受信者への互換性は、新しい送信者の構築責任だった。未知の新規フィールドを除いても、旧版として有効なメッセージが残らなければならない。

次のようなリクエストを考える。

GET /records HTTP/1.1

本文はなく、新しいキャッシュ指示もなく、目立つ拡張機能もない。それでも末尾がHTTP/1.1であることに矛盾はない。数字は「この一通で1.1の機能を使い切った」と報告しているのではないからだ。直接の受信者に対し、送信者がどの形式で話しており、次の応答や後続のリクエストでどこまで理解できるかを知らせている。

この違いを守ると、バージョン番号から読み取れる範囲が明確になる。番号は次の判断材料にはなる。しかし、特定機能の実行、全経路の同一性、最終到達、アプリケーション処理の成功まで証明することはない。

HTTP/1.0の時点で、名称と実装はずれていた

1996年5月のRFC 1945は、HTTP/1.0をインターネット標準としてではなく、広く使われていた慣行として記録した。多くの実装で一貫していた機能は本文に、実装が少ないか不統一だった機能は付録に置かれた。

それでもバージョン節には、後のRFC 2068につながる原則が既にある。番号は、送信者が使う形式と今後のHTTP通信を理解する能力を示すのであって、その通信で得られた機能を表すのではない。

RFC 2068の序文は、HTTP/1.0を名乗りながら実装が不完全なアプリケーションが増えたことにも触れている。製品名や自己申告だけでは、相手が次に何を処理できるか分からない。そこでワイヤ上の番号に、適合性に裏打ちされた意味を与える必要があった。

メジャー番号は、メッセージ形式が変わるときに上がる。マイナー番号は、一般的な解析手順を変えずに意味や送信者能力が増えるときに上げられる。すでに拡張可能なフィールドへ値を足すだけで通信動作が変わらないなら、必ずしも新しい番号は要らない。

この分担は、古い受信者にも読める共通骨格と、新しい参加者が追加できる余地を同時に守るためのものだった。

数字が示したのは能力の上限

RFC 2068は、そこで定義されたリクエストやレスポンスを送るアプリケーションに、先頭行でHTTP/1.1を示すよう求めた。この番号を使うことは、送信アプリケーションが少なくとも条件付きで仕様に適合するという主張だった。アプリケーションのHTTPバージョンは、条件付き適合を満たす最も高い版とされた。

ここには三つの別々の記録がある。第一は、いまのメッセージをどう解析するかという形式。第二は、送信者が責任を持てる能力の上限。第三は、このメッセージで実際に使われた機能である。

第三の集合は第二より小さくてよい。単純なHTTP/1.1リクエストは、分割転送も持続接続も目立つ新規フィールドも使わない場合がある。それでも番号は、受信者が後でより進んだ応答を返せる可能性を伝える。

逆方向の推論は危険だ。HTTP/1.1を見ても、特定機能が作動したこと、相手の実装が完全であること、すべての中継が同じフィールドを維持したこと、処理が保存または完了したことは分からない。番号は認証情報でも暗号署名でもない。規格は正しい主張の意味を定義するが、虚偽やバグを物理的に防ぐわけではない。

プロキシは次のホップで自分の版を名乗る

HTTPプロキシは、受信したバイト列をそのまま運ぶだけとは限らない。リクエストを解析し、フィールドを変更し、キャッシュから応答し、別の相手へ新しいメッセージを作ることがある。RFC 2068は、そのプロキシやゲートウェイが実際の能力より高いバージョンを送信してはならないとした。

自分より高い版のリクエストを受けた場合、選択肢は明確だった。送信時の版を下げる、エラーを返す、またはトンネルとして動作し解釈をやめる。自分より低い版を受けたときには、条件に応じて上げて転送することもできた。版の変換では、フィールドの追加や削除が必要になり得る。

つまり、上流クライアントの能力はプロキシへ譲渡されない。HTTP/1.0しか実装していないプロキシが、受信したHTTP/1.1を出力へ写せば、次の相手に自分が果たせない約束をすることになる。新しいメッセージを生成した時点で、そのプロキシが送信者である。

同年5月のRFC 2145は、この点をホップ単位の性質として明記した。HTTPバージョン番号はエンドツーエンドの部品ではなく、プロキシはリクエストやレスポンスの番号をそのまま「転送」しない。上流の各区間についてはViaが別の記録を残せるが、現在の先頭行にある番号とは目的が違う。

したがって、オリジンサーバーが受け取ったHTTP/1.1は、直前の隣接送信者についての主張である。元のブラウザーから全区間が同じ版だったと証明するには、各ホップの観測が必要になる。

未知フィールドを外しても成立するか

RFC 2145が必要になったのは、既存文書の読み方に混乱と不一致があり、相互運用上の問題が起きたからだった。そこで同一メジャー版の基本を固定した。マイナー版が上がっても、既存ヘッダーフィールドの解釈を変えてはならない。マイナー番号が示すのは送信者能力であり、メッセージ全体の新しい読み方ではない。

高い版の送信者は、古い受信者が知らないフィールドを送ることができる。ただし、古い相手がそれを理解することに依存してはいけない。HTTP/1.1からHTTP/1.0、または版が不明な相手へ送るメッセージは、HTTP/1.0にないフィールドを取り除いても有効なHTTP/1.0メッセージとして残る必要があった。

互換性の負担を負うのは、新しい能力を選んだ送信者である。古い受信者は未来を予測する必要がない。新しいフィールドが消えても、古い共通部分だけで正しいメッセージになるよう構築しなければならない。

未知フィールドの扱いにも境界がある。プロキシは一般に、知らないフィールドをさらに先へ転送する。自分が理解しなくても、下流の受信者が理解する可能性があるからだ。ただしConnectionで現在の接続専用と示されたフィールドは、次のホップへ送ってはいけない。

また、メッセージ境界に不可欠な機能を「無視できる追加」として扱うこともできない。RFC 2145は、HTTP/1.0リクエストへのレスポンスで分割転送を使ってはならない例を挙げた。古いクライアントがTransfer-Encoding: chunkedを理解しなければ、本文を正しく区切れない。

未知部分を無視する設計は、残る部分だけで意味と構造が完結する場合に限って成立する。

二つの数字を説明するために、なぜ別のRFCが要ったのか

RFC 2145は、バージョン政策の意味を変更する文書ではなく、HTTP/1.0とHTTP/1.1の設計意図を曖昧さのある箇所で確定する文書だと述べる。混乱が実装の不一致と相互運用問題につながったことは示すが、製品名、件数、普及率は示さない。

送る番号の選択も整理された。クライアントは、既知のサーバーが支えるメジャー版を超えない範囲で、自分が少なくとも条件付き適合する最高版を通常は送る。サーバーも、リクエストのメジャー版を超えない範囲で、自分の最高適合版を返す。どちらも適合していない版を名乗れない。

既知の不具合を持つ相手のために低い版を送る余地は残されたが、実際に誤動作を確認した後の例外である。最初から常に低く名乗れば、正しい実装が新しい能力を利用できず、ネットワークは壊れた相手に合わせて固定される。高く偽れば、相手は存在しない能力に依存してしまう。

1999年のRFC 2616はこの意味を引き継ぎ、RFC 2145を参照した。2014年のRFC 7230は両方を置き換え、マイナー番号が将来通信の能力を広告することを明確化した。現在のメッセージが後方互換な小さな機能集合しか使わなくても同じである。

RFC 7230は、RFC 2068からRFC 2616への改訂でマイナー番号が上がらなかったことも記録した。文書が新しくなること、規定が修正されること、ワイヤ上の版が変わることは別の出来事だった。

2022年のRFC 9110は、HTTPの共通意味をHTTP/1.1、HTTP/2、HTTP/3それぞれのメッセージ構文から分離した。三つのメジャー版は単純な新旧関係で消し合わない。中継者がメッセージを送るとき、版はその中継者が次の区間で使うプロトコルを反映し、Viaが上流区間の情報を別に残す。

文書、表示、実装、実行を分ける

Lu Hengが後に提示したMinimum Initial Specification、Localized Future Decision、Voluntary Adoptionは、この歴史を読む編集上のレンズになる。共通層は相互運用に必要な決定的規則へ絞る。各参加者は自分が動かすコードで互換性を判断する。新しい仕様は、公開された瞬間ではなく、実装・検証・利用されたときに運用上の現実になる。

これは1997年の著者意図を示す証拠ではなく、分散台帳や制度設計についてHTTP文書がLu Hengの主張を採用したという意味でもない。使えるのは、公開RFC、表示されたバージョン、実装能力、今回使った機能、配送、最終結果を別々に評価する姿勢である。

RFC 2068の番号は、ウェブ全体を一度に認証しようとしなかった。各送信者に、自分が発するメッセージの形式と能力だけを引き受けさせた。古い相手には、新しい部分を外しても壊れないメッセージを残させた。その狭さが、段階的な進化を可能にした。

出典