この文書は「RFC 9113」の日本語訳です。
原文の最新版は、この日本語訳が参照した版から更新されている可能性があります。
この日本語訳は参考情報であり、正式な文書ではないことにも注意してください。また、翻訳において生じた誤りが含まれる可能性があるため、必ず原文もあわせて参照することを推奨します。
この仕様は、HTTP バージョン2 (HTTP/2) と呼ばれる、最適化された Hypertext Transfer Protocol (HTTP) のセマンティクス表現について説明します。HTTP/2 は、フィールド圧縮を導入し、同一接続上での複数同時通信の実現により、ネットワークリソースのより効率的な利用とレイテンシの削減を可能にします。
この仕様は RFC 7540 と RFC 8740 を廃止します。
これは Internet Standards Track 文書です。
この文書は Internet Engineering Task Force (IETF) の成果物です。これは、IETF コミュニティの合意を表現するものであり、公開の査読を受け、Internet Engineering Steering Group (IESG) により発行が承認されました。Internet Standards に関するさらなる情報は RFC 7841 の2章に記述されています。
この文書の現在の状態やエラッタ、フィードバックの提供方法についての情報は https://www.rfc-editor.org/info/rfc9113 で参照できます。
Copyright (c) 2022 IETF Trust and the persons identified as the document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.
Hypertext Transfer Protocol (HTTP, [HTTP]) を使用するアプリケーションのパフォーマンスは、HTTP の各バージョンが使用するトランスポートと、そのトランスポートが動作する条件に関係があります。
複数のリクエストを同時に行うことでレイテンシを削減し、アプリケーションのパフォーマンスを向上できます。HTTP/1.0 は与えられた TCP [TCP] 接続に対して、同時に発行できるリクエストは1つだけでした。HTTP/1.1 [HTTP/1.1] ではリクエストパイプラインが追加されましたが、それはリクエストの並列化に部分的に対処しただけで、今でもアプリケーション層の行頭ブロッキングに悩まされています。そのため、HTTP/1.0 や HTTP/1.1 のクライアントはサーバーへの複数の接続を使用して同時にリクエストをします。
さらに HTTP フィールドは重複して冗長であることが多く、不必要なネットワークトラフィックを引き起こすだけでなく、初期の TCP 輻輳ウインドウをすぐに埋め尽くしてしまいます。その結果、新しい TCP 接続上で複数のリクエストが行われると、過剰な遅延が発生することになります。
HTTP/2 では、基礎となる接続に対して HTTP セマンティクスの最適化マッピングを定義することによって、これらの問題に取り組みます。具体的には、同一接続上においてメッセージを相互に織り交ぜたり、HTTP フィールドの効率のよい符号化方式を利用します。またリクエストの優先度付けも可能にし、重要なリクエストをより迅速に完了させることで更なるパフォーマンス向上を実現します。
この結果からもたらされるプロトコルは、HTTP/1.x と比較して使用する TCP 接続が少なくなり、よりネットワークに優しいものになります。これは他のフローとの競合を減らし、接続寿命が長くなることを意味します。そして結果的に、利用可能なネットワークキャパシティの有効利用につながることになります。ただし、TCP の行頭ブロッキングはこのプロトコルでは解決しないことに注意してください。
最後に、HTTP/2 では、バイナリメッセージ構造を使用することで、より効率的なメッセージ処理を可能にします。
この文書は RFC 7540 と 8740 を廃止します。付録Bに注目すべき変更点を示します。
HTTP/2 は HTTP セマンティクスの最適化された転送手段を提供します。HTTP/2 は HTTP の主要な機能の全てに対応しますが、HTTP/1.1 よりも効率的であることを目指します。
HTTP/2 は TCP ([TCP]) 接続上で動作する接続指向のアプリケーション層プロトコルです。クライアントが TCP 接続を開始します。
HTTP/2 におけるプロトコルの基本的な単位はフレーム (4.1節) です。フレームの種類により用途が異なります。例えば、HEADERS と DATA フレームは HTTP リクエストとレスポンス (8.1節) の基礎を構成します。SETTINGS、WINDOW_UPDATE、PUSH_PROMISE といったその他のフレームタイプは他の HTTP/2 の機能に対応するために使われます。
リクエストの多重化は、各 HTTP リクエスト/レスポンスを単一のストリーム (5章) に割り当てることで実現します。ストリームは他のストリームとは独立しているため、リクエストのブロックや停止が、他のリクエストの進捗を妨げることはありません。
多重化の効果的な利用は、フロー制御と優先度付けに依存します。フロー制御は (5.2節) は、送信されるデータを受信者が適切に処理可能な範囲に制限することで多重化されたストリームを効率的に利用可能にします。優先度付け (5.3節) は限られたリソースを最も効果的に使用することを確実にします。この HTTP/2 の改訂では [RFC7540] の優先度通知の仕組みを非推奨にします。
接続で使用される HTTP フィールドには、多くの冗長なデータを含む可能性があるため、フィールドを含むフレームは圧縮されます (4.3節)。これは、多くのリクエストを1つのパケットに圧縮できるため、一般的なリクエストのサイズにおいて特に有益な効果があります。
最後に、HTTP/2 では、サーバーからクライアントにレスポンスをプッシュできる新しいオプションとなるインタラクションモードを追加します (8.4節)。これは、潜在的なレイテンシの増加とネットワーク利用のトレードオフとして、サーバーがクライアントが必要とするデータを予測して投機的なクライアントへのデータ送信を可能にすることを意図しています。サーバーは PUSH_PROMISE フレームとして送信されるリクエストを合成することで、これを実行します。その後、サーバーは合成したリクエストに対するレスポンスを別のストリームで送信できます。
HTTP/2 の仕様は4つのパートで構成されます:
フレーム層やストリーム層の概念の一部は HTTP から分離されていますが、この仕様では完全に汎用的なフレーム層を定義するわけではありません。フレーム層とストリーム層は HTTP の要件にあわせて作られました。
この文書のキーワード "MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"NOT RECOMMENDED"、"MAY"、そして "OPTIONAL" はここに示すようにすべて大文字で出現した場合にのみ BCP 14 [RFC2119] [RFC8174] に記載されている通りに解釈するものとします。
すべての数値はネットワークバイトオーダーです。特に断りがない限り、値は符号なしとなります。リテラルの値は、必要に応じて10進数または16進数で提供されます。また、16進数リテラルは10進数リテラルと区別するために "0x" ではじまります。
この仕様では、RFC 9000 [QUIC] の1.3節で説明されている規約を使用してバイナリフォーマットを記述します。このフォーマットはネットワークバイトオーダーを使用し、上位ビットが下位ビットの前に記載されることに注意してください。
使用される用語は以下のとおりです:
最後に、"ゲートウェイ"、"中継者"、"プロキシ" そして "トンネル" の用語は [HTTP] の3.7節で定義されています。中継者は状況によりクライアントとサーバーのどちらとしても振舞います。
メッセージボディに使用する "コンテンツ" は [HTTP] の6.4節で定義されています。
HTTP リクエストを送信する実装は、サーバーが HTTP/2 に対応しているかどうかを検出する必要があります。
HTTP/2 は、HTTP/1.1 [HTTP1.1]と同じデフォルトのポート番号と共に、[HTTP]の4.2節で定義された "http" と、"https" URI スキームを使用します。これらの URI には、アップストリームサーバー (クライアントがコネクションを確立しようとしている直接のピア) がどの HTTP バージョンに対応しているかの情報は含まれていません。
HTTP/2 への対応を決定する手段は "http" と "https" の URI で異なります。"https" URI での検出については3.2節で説明します。"http" URI での HTTP/2 の対応は帯域外の手段によってのみ検出でき、3.3節で説明するように対応についての事前知識を必要とします。
この文書で定義されるプロトコルの識別子は2つあります。このいずれかに基づいて接続を生成することはこの文書で説明される転送手段、フレーミング、メッセージセマンティクスの使用を意味します。
文字列 "h2" は Transport Layer Security (TLS、9.2節を参照) を使用する HTTP/2 プロトコルを識別します。この識別子は TLS Application-Layer Protocol Negotiation (ALPN) 拡張 [TLS-APLN] フィールドや、TLS 上の HTTP/2 であることが識別される全ての場所において使用されます。
文字列 "h2" は、2つのオクテット 0x68, 0x32 として、ALPN プロトコル識別子にシリアライズされます。
文字列 "h2c" は HTTP アップグレードメカニズムの Upgrade ヘッダーフィールド ([HTTP] の7.8節) におけるトークンとして使用されました。これは広くデプロイされず、この文書で非推奨になりました。HTTP2-Settings ヘッダーフィールドについても同様で、これは "h2c" へのアップグレードに利用されました。
>"https" URI へのリクエストをするクライアントは、TLS [TLS13] と ALPN 拡張 [TLS-ALPN] を利用します。
TLS 上の HTTP/2 は "h2" プロトコル識別子を使用します。"h2c" プロトコル識別子はクライアントから送信されたり、サーバーにより選択されてはいけません (MUST NOT)。"h2c" プロトコル識別子は TLS を使用しないプロトコルを示します。
TLS ネゴシエーションが完了すると、クライアントとサーバーはコネクションプリフェイス (3.4節) を送信しなければなりません (MUST)。
クライアントは、他の方法で特定のサーバーが HTTP/2 に対応しているのを知ることができます。例えば、あるサーバーが HTTP/2 に対応していることを知った上でクライアントを設定できます。
サーバーが HTTP/2 に対応していることを知っているクライアントは、TCP 接続を確立し、コネクションプリフェイス (3.4節) に続いて HTTP/2 フレームを送信できます。サーバーはコネクションプリフェイスの存在により、このような接続を識別できます。これは平文 TCP 上の HTTP/2 接続の確立にのみ影響し、TLS 上の HTTP/2 接続に対応する実装は、TLS のプロトコルネゴシエーション [[TLS-ALPN]] を使用しなければなりません (MUST)。
同様に、サーバーもコネクションプリフェイス (3.4節) を送信しなければなりません (MUST)。
追加情報がなければ、HTTP/2 の事前知識は将来の接続に対しても指定されたサーバーが HTTP/2 に対応するという強いシグナルにはなりません。例えば、サーバーの構成の変更や、クラスター化されたサーバーインスタンス間で異なったり、ネットワークの状態変更といったことが起こり得ます。
HTTP/2 では、各エンドポイントはプロトコルの使用の最終確認と、HTTP/2 コネクションの初期設定を確立するために、コネクションプリフェイスを送信する必要があります。クライアントとサーバーはお互いに異なるコネクションプリフェイスを送信します。
クライアントコネクションプリフェイスは、24オクテットの配列ではじまり、16進数表現は以下のようになります:
0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
つまり、コネクションプリフェイスは "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" で始まります。この配列の後には、SETTINGS フレーム (6.5節) が続かなければなりません (MUST)。この SETTINGS フレームは空であってもよいものとします。クライアントは接続における最初のアプリケーションデータオクテットとしてクライアントコネクションプリフェイスを送信します。
注: 多数の HTTP/1.1 や HTTP/1.0 のサーバー、中継システムがさらにフレームを処理しないよう、このクライアントコネクションプリフェイスが選ばれました。これは、[TALKING] で提起された懸念には対応しないことに注意してください。
サーバーコネクションプリフェイスは空の可能性がある SETTINGS フレーム (6.5節) だけで構成され、HTTP/2 接続においてサーバーが送信する最初のフレームでなければなりません (MUST)。
ピアからコネクションプリフェイスの一部として受信した SETTINGS フレームは、コネクションプリフェイスの送信後にその適用を通知 (6.5.3節) しなけければなりません (MUST)。
不要なレイテンシを防ぐために、クライアントはクライアントコネクションプリフェイスの送信後、サーバーコネクションプリフェイスの受信を待たずに、すぐに追加のフレームをサーバーに送信することが認められています。しかしながら、サーバーコネクションプリフェイスの SETTINGS フレームが、クライアントがサーバーとどのように通信するかを変更する設定を含む可能性があることに注意しなければなりません。クライアントは SETTINGS フレームを受信後に直ちに全ての設定に従うことが求められます。一部の構成では、クライアントが追加のフレームを送信する前に、この問題を回避する機会を提供するためにサーバーが SETTINGS を送信できますs。
クライアントとサーバーは、不正なコネクションプリフェイスを PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。ピアが HTTP/2 を使用していないことを不正なプリフェイスが示している場合は GOAWAY フレーム (6.8節) を省略してもよいものとします (MAY)。
HTTP/2 接続が確立されると、クライアントとサーバーはフレームの送信を開始できます。
全てのフレームは、9オクテット固定長のヘッダーから始まり、可変長のフレームペイロードがその後に続きます。
HTTP Frame { Length (24), Type (8), Flags (8), Reserved (1), Stream Identifier (31), Frame Payload (..), } 図1: フレームレイアウト
フレームヘッダーのフィールドは以下のように定義されます:
フレームペイロードの構造と内容については、フレームタイプに完全に依存します。
フレームペイロードのサイズは、SETTINGS_MAX_FRAME_SIZE 設定で受信者が通知した最大サイズにより制限されます。この設定は 2^14 (16,384) から 2^24-1 (16,777,215) までのオクテットの値を持つことができます。
全ての実装は、2^14オクテットまでの長さのフレームと9オクテットのフレームヘッダー (4.1節) を受信し、最低限処理できなければなりません (MUST)。フレームサイズを記述する場合は、フレームヘッダーのサイズは含まれません。
注: PING (6.7節) のような特定のフレームタイプでは、フレームペイロードデータの量について追加の制限があります。
フレームが、SETTINGS_MAX_FRAME_SIZE で定義されたサイズやフレームタイプで定義された制限を超えていたり、必須となるフレームデータを含むには小さすぎるような場合、エンドポイントは FRAME_SIZE_ERROR のエラーコードを送信しなければなりません (MUST)。接続の状態を変更可能なフレームにおけるフレームサイズエラーは、コネクションエラー (5.4.1節) として扱われなければなりません (MUST)。これらの対象には、フィールドブロック (4.3節) を転送するフレーム (つまり HEADERS や PUSH_PROMISE、CONTINUATION) や SETTINGS フレーム、ストリームID が 0 の全てのフレームが含まれます。
エンドポイントには、フレームの全ての利用可能な領域を使用する義務はありません。許可された最大サイズよりも小さいフレームを使用することで、応答性を改善できます。巨大なフレームの送信は (RST_STREAM、WINDOW_UPDATE、PRIORITY といった) 時間に敏感なフレームの送信遅延を引き起こし、巨大なフレームの送信によりそれらのフレームがブロックされた場合、パフォーマンスに影響を与えます。
フィールドセクションの圧縮とは、フィールドブロックとなる一連のフィールド行 ([HTTP] の5.2節) をフィールドブロックに圧縮する処理です。フィールドセクションの伸長とは、フィールドブロックを一連のフィールド行に展開する処理です。HTTP/2 フィールドセクションの圧縮と伸長の詳細は [COMPRESSION] で定義されていますが、歴史的な理由により、これらの処理はヘッダーの圧縮と伸長と呼んでいます。
各フィールドブロックは、単一のフィールドセクションの圧縮されたフィールド行の全てを保持します。ヘッダーセクションには、フィールド行と同じフォーマットを使用する疑似ヘッダーフィールド (8.3節) として、メッセージに関連する制御データも含まれます。
注: RFC 7540 [RFC7540] では、より一般的な「フィールドブロック」の代わりに「ヘッダーブロック」という用語が使用されました。
フィールドブロックは制御データとリクエストやレスポンス、予約されたリクエスト、そしてプッシュレスポンス (8.4節 を参照) のヘッダーセクションを保持します。PUSH_PROMISE (6.6節) フレームに含まれる中間レスポンスやリクエストを除き、これらの全てのメッセージにはトレイラーセクションを保持するフィールドブロックを含めることができます。
フィールドセクションはフィールド行の集合です。フィールドブロックの各フィールド行は1つの値を保持します。シリアライズされたフィールドブロックは、フィールドブロックフラグメントと呼ばれる1つ以上のオクテット列に分割されます。最初のブロックフラグメントは HEADERS (6.2節) または PUSH_PROMISE (6.6節) のフレームペイロードで転送され、または CONTINUATION (6.10節) フレームのペイロードとして転送され、各フレームには後続のフィールドブロックフラグメントを転送する CONTINUATION (6.10節) フレームが続く可能性があります。
Cookie ヘッダーフィールド [COOKIE] は HTTP マッピングにより特別に処理されます (8.2.3節)。
受信側エンドポイントはフラグメントを結合してフィールドブロックを再構築し、フィールドセクションを復元するために伸張します。
完全なフィールドセクションは次のいずれかで構成されます:
各フィールドブロックは別々の単位として処理されます。フィールドブロックは、他の種類のフレームや他のストリームのフレームの間に挟み込まれずに、連続した一連のフレームとして送信されなければなりません (MUST)。一連の HEADERS や CONTINUATION フレームの最後のフレームには、END_HEADERS フラグが設定されます。また、一連の PUSH_PROMISE や CONTINUATION フレームの最後のフレームにも、END_HEADERS フラグが設定されます。これにより、フィールドブロックを論理的に単一のフレームと同等にできます。
フィールドブロックフラグメントは HEADERS、PUSH_PROMISE、CONTINUATION フレームのフレームペイロードでのみ送信できます。これらのフレームは、受信者が保持する圧縮コンテキストを変更するデータを転送するためです。HEADERS、PUSH_PROMISE、CONTINUATION フレームを受信したエンドポイントは、フレームの破棄が発生したような場合であっても、フィールドブロックを再構築し、伸張する必要があります。フィールドブロックを伸張できない場合、受信者は COMPRESSION_ERROR のコネクションエラー (5.4.1節) と共にコネクションを終了しなければなりません (MUST)。
フィールドブロックの伸長エラーは COMPRESSION_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。
フィールド圧縮は状態を持ちます。各エンドポイントはコネクション上の全てのフィールドブロックのエンコードとデコードに使用する HPACK エンコーダーコンテキストと HPACK デコーダーコンテキストを持ちます。[COMPRESSION] の4章では各コンテキストの主な状態となる動的テーブルを定義しています。
動的テーブルの最大サイズは HPACK デコーダーにより設定されます。エンドポイントのは自身の HPACK デコーダーコンテキストが選択するサイズを SETTINGS_HEADER_TABLE_SIZE 設定 (6.5.2節を参照) 使用してやりとりします。コネクションが確立した時、両方のエンドポイントの HPACK デコーダーとエンコーダーの動的テーブルサイズは、SETTINGS_HEADER_TABLE_SIZE 設定の初期値である 4,096 バイトで始まります。
SETTINGS_HEADER_TABLE_SIZE を使用して設定される最大値の変更は、エンドポイントが設定に応答した時に有効になります (6.5.3節)。そのエンドポイントの HPACK エンコーダーは、デコーダーが設定した最大値まで動的テーブルを任意のサイズに設定できます。HPACK エンコーダーは Dynamic Table Size Update ([COMPRESSION] の6.3節) 命令により動的テーブルのサイズを宣言します。
"ストリーム" とは、HTTP/2 接続においてクライアントとサーバーとの間で交換されるフレームの独立した双方向シーケンスです。ストリームにはいくつかの重要な特徴があります:
ストリームのライフサイクルは、図2に示すようになります。
+--------+ send PP | | recv PP ,--------+ idle +--------. / | | \ v +--------+ v +----------+ | +----------+ | | | send H / | | ,------+ reserved | | recv H | reserved +------. | | (local) | | | (remote) | | | +---+------+ v +------+---+ | | | +--------+ | | | | recv ES | | send ES | | | send H | ,-------+ open +-------. | recv H | | | / | | \ | | | v v +---+----+ v v | | +----------+ | +----------+ | | | half- | | | half- | | | | closed | | send R / | closed | | | | (remote) | | recv R | (local) | | | +----+-----+ | +-----+----+ | | | | | | | | send ES / | recv ES / | | | | send R / v send R / | | | | recv R +--------+ recv R | | | send R / `----------->| |<-----------' send R / | | recv R | closed | recv R | `----------------------->| |<-----------------------' +--------+ 図2: ストリームの状態 send: エンドポイントがフレームを送信 recv: エンドポイントがフレームを受信 H: HEADERS フレーム (CONTINUATION フレームを含む) ES: END_STREAM フラグ R: RST_STREAM フレーム PP: PUSH_PROMISE フレーム (CONTINUATION フレームを含む。この状態遷移は予約されたストリーム用)
このダイアグラムはストリームの状態遷移と、これらの遷移に影響するフレームとフラグのみを表していることに注意してください。なお、CONTINUATION フレームについては状態遷移をもたらさず、実質的に HEADERS や PUSH_PROMISE の一部になります。この状態遷移の目的のために、END_STREAM フラグはそれが設定されたフレームに対して別々のイベントとして処理され、END_STREAM フラグが設定された HEADERS フレームは2つの状態遷移を引き起こす可能性があります。
両方のエンドポイントは、それぞれの立場に応じたストリーム状態図を持ち、フレーム転送中では両者は異なるでしょう。エンドポイントはストリームの作成について互いに連携しません。ストリームはどちらかのエンドポイントにより一方的に作成されます。状態の不一致に伴う悪い影響は、RST_STREAM を送信した後の "closed" 状態に限定されます。その場合クローズ後にしばらくフレームを受信するかもしれません。
ストリームは次のような状態を持ちます:
この状態では、次のような遷移が有効です:
この状態のストリームでの HEADERS や PRIORITY 以外のフレームの受信は、PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。5.1.1節に記載されているように、ストリームがサーバーによって開始される場合、HEADERS フレームの受信も PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。
この状態では、次のような遷移のみ可能です:
この状態において、エンドポイントは HEADERS や RST_STREAM、PRIORITY 以外のいかなる種類のフレームも送信してはいけません。(MUST NOT)。
PRIORITY または WINDOW_UPDATE フレームはこの状態で受信してもよいものとします (MAY)。この状態のストリームでの RST_STREAM や PRIORITY、WINDOW_UPDATE フレーム以外の受信については、PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。
この状態では、次のような遷移のみ可能です:
エンドポイントはこの状態において、RST_STREAM や WINDOW_UPDATE、PRIORITY フレーム以外の種類のフレームを送信してはいけません (MUST NOT)。
この状態のストリームでの HEADERS や RST_STREAM、PRIORITY フレーム以外の受信については、PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。
この状態から、どちらのエンドポイントも END_STREAM フラグを設定したフレームを送信できます。それによって、ストリームは "half-closed" 状態に遷移します。すなわちエンドポイントが END_STREAM フラグを送信すると、ストリームの状態は "half-closed (local)" となり、エンドポイントが END_STREAM フラグを受信した場合は、ストリームの状態が "half-closed (remote)" になります。
この状態では、どちらのエンドポイントも直ちに "closed" に遷移させる RST_STREAM フレームを送信できます。
END_STREAM フラグが設定されたフレームを受信するか、いずれかのピアが RST_STREAM フレームを送信した時、ストリームはこの状態から "closed" に遷移します。
エンドポイントは、この状態ではいかなるフレームも受信できます。WINDOW_UPDATE フレームを使用してフロー制御情報を提供することは、フロー制御下のフレームの受信を続けるために必要です。受信者は、END_STREAM フラグが設定されたフレームを送信した後の短時間に到着する可能性がある WINDOW_UPDATE をこの状態では無視できます。
この状態では PRIORITY フレームを受信できます。
エンドポイントが、この状態にあるストリームから WINDOW_UPDATE や PRIORITY、RST_STREAM 以外の追加のフレームを受信した場合は、STREAM_CLOSED のストリームエラー (5.4.2節) を返さなければなりません (MUST)。
"half-closed (remote)" のストリームは、エンドポイントが任意の種類のフレームの送信に使用できます。この状態では、エンドポイントは通知されたストリームレベルのフロー制御の制限 (5.2節) を守り続けます。
ストリームは、END_STREAM フラグが設定されたフレームを送信するか、いずれかのピアが RST_STREAM フレームを送信することで、この状態から "closed" 状態に遷移できます。
エンドポイントが END_STREAM フラグを設定されたフレームを送受信した後、ストリームは "closed" 状態になります。エンドポイントが RST_STREAM フレームを送受信した後も同様に、ストリームは "closed" 状態になります。
エンドポイントは closed ストリームに PRIORITY 以外のフレームを送信してはいけません (MUST NOT)。また、エンドポイントは以下で説明する場合を除き、closed ストリームでの他の種類のフレームの受信を STREAM_CLOSED のコネクションエラー (5.4.1節) として扱ってもよいものとします (MAY)。
END_STREAM フラグを設定したフレームや RST_STREAM フレームを送信するエンドポイントは、ストリームを閉じるフレームをピアが受信して処理するまでの間にピアから WINDOW_UPDATE または RST_STREAM フレームを受信する可能性があります。
"open" または "half-closed (local)" 状態のストリームに RST_STREAM フレームを送信したエンドポイントは、あらゆる種類のフレームを受信する可能性があります。ピアは RDS_STREAM フレームを処理する前に、フレームを既に送信していたり、送信キューに入れていたりするかもしれません。エンドポイントはこの状態で受信したフレームを最低限処理し、そして破棄しなければなりません (MUST)。これは HEADERS や PUSH_PROMISE フレームのヘッダー圧縮状態を更新することを意味します。PUSH_PROMISE フレームの受信は、たとえ閉じたストリームで PUSH_PROMISE フレームを受信したとしても、予約済みストリームを "reserved (remote)" 状態にします。さらに、DATA フレームの内容はコネクションフロー制御のウインドウに数えられます。
エンドポイントは "closed" 状態にある全てのストリームに対して、最小限の処理を実行できます。エンドポイントは他のシグナルを使用して、ストリームが "closed" 状態になるフレームをピアが受信したことを検出し、PRIORITY 以外のフレームの受信を PROTOCOL_ERROR タイプのコネクションエラー (5.4.1節) として扱ってもよいものとします (MAY)。エンドポイントは、これを推進するするためにピアが終了シグナルを受信したことを示すフレーム使用できます。エンドポイントはこの目的にタイマーを使用するべきではありません (SHOULD NOT)。例えば、ストリームを閉じた後に SETTINGS フレームを送信するエンドポイントは、設定の応答を受信後にそのストリームでの DATA フレームの受信をエラーとして安全に扱うことができます。他にも、PING フレームやストリームを閉じた後に作成されたストリームでのデータの受信、ストリームを閉じた後に作成されたリクエストに対するレスポンスが使われるかもしれません。
より具体的なルールがない場合、実装は状態の説明で明示的に許可されていないフレームの受信を PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱うべきです (SHOULD)。なお、PRIORITY はどのようなストリームの状態においても送受信できることに注意してください。
この章のルールは、この文書で定義されるフレームにのみ適用されます。セマンティクスが不明なフレームの受信は、それらのフレームの送受信の条件も不明であるため、エラーとしては扱えません。5.5節を参照してください。
HTTP リクエスト/レスポンスの交換における状態遷移の例は、8.8節で確認できます。サーバープッシュの状態遷移の例は、8.4.1節と8.4.2節で確認できます。
ストリームは、符合なし31ビットの整数で識別されます。クライアントが開始したストリームは奇数のストリームIDを使わなければなりません (MUST)。また、サーバーが開始したストリームは偶数のストリームIDを使わなければなりません (MUST)。ストリームID 0 (0x00) は、コネクション制御メッセージに使用されます。ストリームID 0 は新しいストリームの確立には使用できません。
新しく確立されるストリームIDは、エンドポイントがすでに開始または予約した全てのストリームよりも大きい数値でなければなりません (MUST)。この影響を受けるのは、HEADERS フレームを使用して開始されたストリームと、PUSH_PROMISE を使用して予約されたストリームです。予期せぬストリームIDを受信したエンドポイントは、PROTOCOL_ERROR タイプのコネクションエラー (5.4.1節) を返さなければなりません (MUST)。
HEADERS フレームは、フレームヘッダーのストリームIDで識別されるクライアントが開始したストリームを "idle" から "open" に遷移させます。PUSH_PROMISE フレームは、フレームペイロードの Promised Stream ID フィールドで識別されるサーバーが開始したストリームを "idle" から "reserved (local)" または "reserved (remote)" に遷移させます。ストリームが "idle" から遷移すると、ピアからより小さい値のストリームIDで開かれた可能性のある"idle" 状態にある全てのストリームは直ちに "closed" 状態に遷移します。つまり、エンドポイントはストリームIDをスキップでき、スキップされたストリームは直ちに終了する効果があります。
ストリームIDは再利用できません。長時間のコネクションでは、エンドポイントがストリームIDの利用可能な範囲を越えてしまう可能性があります。新しいストリームIDを生成できないクライアントは、新しいストリームのために新たなコネクションを確立できます。新しいストリームIDを確立できないサーバーは、新しいストリームのために新しいコネクションを開始することをクライアントに強制するために、GOAWAY フレームを送信できます。
ピアは、SETTINGS フレームの SETTINGS_MAX_CONCURRENT_STREAMS パラメーター (6.5.2節) を使用することで、同時アクティブなストリームの数を制限できます。最大同時ストリーム設定は各エンドポイントに固有であり、その設定を受信したピアにのみ適用されます。つまり、クライアントはサーバーが開始可能な同時ストリームの最大数を指定し、サーバーはクライアントが開始可能な同時ストリームの最大数を指定します。
エンドポイントが開始可能なストリームの最大数は、"open" または2つの "half-closed" 状態のストリームの数で計算されます。これら3つの状態にあるストリームは SETTINGS_MAX_CONCURRENT_STREAMS 設定で指定された制限に数えられます。2つの "reserved" 状態にあるストリームは、このストリーム制限には数えられません。
エンドポイントはお互いのピアが設定した制限を超えてはいけません (MUST NOT)。告知した同時ストリーム制限を超えるような HEADERS フレームを受信したエンドポイントは、それを PROTOCOL_ERROR または REFUSED_STREAM のストリームエラー (5.4.2節) として扱わなければなりません (MUST)。エラーコードの選択は、エンドポイントが自動再試行を有効にするかどうかに影響します。この詳細は8.7節を参照してください。
SETTINGS_MAX_CONCURRENT_STREAMS を現在の同時ストリーム数よりも少ない値に設定したいエンドポイントは、新しい値を超えるストリームを終了するか、完了させることができます。
ストリームの多重化を使用すると、TCP 接続を使用する上で競合が発生し、その結果ストリームのブロックが起こります。フロー制御の仕組みは、同一コネクション上でストリームが互いに破壊的な干渉をしないことを保証します。フロー制御は、個々のストリームとコネクション全体のどちらにも使用されます。
HTTP/2 では、WINDOW_UPDATE フレーム (6.9節) の使用を通じて、フロー制御を提供します。
HTTP/2 のストリームフロー制御は、プロトコルの変更の必要なしに、様々なフロー制御アルゴリズムを適用することを目標にしています。HTTP/2 におけるフロー制御は以下のような特徴があります:
実装には送信するリクエストやレスポンスの優先度付けや、リクエストの行頭ブロッキングを防ぐ方法の選択、新しいストリームの作成の管理などをする責任があります。これらのアルゴリズムの選択肢は、フロー制御アルゴリズムと相互に影響します。
フロー制御は、リソース制限下で動作しているエンドポイントを保護するために定義されています。例えばプロキシは、多くのコネクションの間でメモリーを共有する必要があり、そこには低速なアップストリームや高速なダウンストリームを含む可能性があるでしょう。フロー制御は、受信者があるストリームのデータの処理ができない状況であっても、同一コネクション上の他のストリームの処理を継続したい場合に対応します。
この機能を必要としない構成では、最大サイズ (2^31-1) のフロー制御ウインドウを通知し、データの受信時に WINDOW_UPDATE フレームを送信することで、このウインドウを維持できます。これは受信者におけるフロー制御を実質的に無効化します。反対に、送信者は常に受信者により通知されたフロー制御ウインドウの影響を受けます。
リソース (例えばメモリーなど) が制限された構成では、ピアが使用するメモリーの量を制限するために、フロー制御を使用できます。しかしながら、帯域幅遅延積 ([RFC7323]) についての知識なしにフロー制御を有効化した場合、利用可能なネットワークリソースを適切に利用できない可能性があることに注意してください。
最新の帯域幅遅延積についての十分な知識があるとしても、フロー制御の実装は困難である可能性があります。エンドポイントはデータが利用可能になり次第、TCP 受信バッファから HTTP2 フレームを読み込んで処理をしなければなりません (MUST)。迅速な読み込みに失敗すると、WINDOW_UPDATE のような重要なフレームの読み込みと処理ができず、デッドロックを引き起こす可能性があります。HTTP/2 のフロー制御によりリソースの利用が制限されるため、フレームを迅速に読み込むことでエンドポイントがリソース枯渇攻撃にさらされることはありません。
エンドポイントが、コネクションにおけるピアの帯域遅延積よりも大きい利用可能なフロー制御ウインドウの領域を常に保持していることが確認できない場合、受信スループットは HTTP/2 のフロー制御により制限されます。その結果、パフォーマンスが低下します。
WINDOW_UPDATE フレームを適時送信することでパフォーマンスを改善できます。エンドポイントは受信スループットの改善する必要性とリソースの枯渇リスクを管理する必要性でバランスをとる必要があり、ウインドウサイズを管理する戦略を定義する場合に10.5節の注意事項をよく考慮するべきです。
HTTP/2 のような多重化プロトコルにおいては、ストリームに対する帯域と計算リソースの割り当てを優先付けることが、優れたパフォーマンスを達成するために重要になり得ます。不十分な優先度付けの仕組みは HTTP/2 のパフォーマンスを低下させる可能性があります。TCP 層で並列処理を行わない場合は、HTTP/1.1 よりも大幅にパフォーマンスが低下する可能性があります。
優れた優先度付けの仕組みは、リソースの内容やリソースの相互関係、リソースがピアにどのように使用されるのかといったコンテキストの知識を適用することで効果を発揮します。特にクライアントは、サーバーでの優先度付けに関連してリクエストの優先度についての知識を持つことができます。このような場合は、クライアントが優先度情報を提供することでパフォーマンスを向上できます。
RFC 7540 ではリクエストの優先度を通知する十分な仕組みを定義しました。しかし、この仕組みは複雑とみなされ、広く実装されていません。
柔軟な仕組みであるがゆえにクライアントは非常に様々な方法で優先度を表現するのが可能であり、採用された手法には一貫性がありませんでした。サーバーにとっては、この仕組みの汎用的な対応を実装するのが困難でした。優先度の実装はクライアントとサーバーの両方でばらつきがありました。多くのサーバーでは、リクエストの処理が優先度付けする際にクライアントの通知を無視していました。
つまり、RFC 7540 [RFC7540]の優先度通知は成功しませんでした。
この HTTP/2 の更新では、RFC 7540 [RFC7540]で定義した優先度通知を非推奨にします。優先度通知に関する多くの文章はこの文書には含まれません。フレームフィールドの説明や一部の必須処理は、この文書の実装が、RFC 7540 で定義された優先度通知を使用する実装と相互運用性を維持することを保証するために残されます。
RFC 7540 の優先度の仕組みの完全な説明は [RFC7540]の5.3節に残されています。
多くの場合、より良いパフォーマンスを達成するために優先度情報の通知は必要です。優先度情報の通知が重要とされる場合は、エンドポイントは [HTTP-PRIORITY] で説明されているような代替の仕組みを使用することが推奨されます。
RFC 7540 の優先度通知は広く採用されませんでしたが、より良い情報がない場面においては優先度通知で提供される情報は有用です。HEADERS や PRIORITY フレームで優先度通知を受信するエンドポイントは、その情報を適用することで恩恵が得られる可能性があります。特に、これらの通知を処理する実装では、代替手段がない場合はこれらの優先度通知を破棄しても恩恵が得られることはないでしょう。
サーバーは、優先度通知がない状況ではリクエストの優先度を決定する際に他のコンテキスト情報を使用するべきです (SHOULD)。サーバーは通知がまったくない状況を、クライアントがその機能を実装していないと解釈してもよいものとします (MAY)。[RFC7540]の5.3.5節で説明されているデフォルト値は、ほとんどの条件下でパフォーマンスが低いことが知られており、それらを意図的に使用することは考えにくいと言えます。
HTTP/2 の枠組みにおいては、2種類のエラーを許可します:
エラーコードのリストは7章にあります。
エンドポイントは複数のエラーを引き起こすフレームに遭遇する可能性があります。実装は処理中に複数のエラーを検出できますが、結果として最大で1つのストリームエラーと1つのコネクションエラーを報告するべきです (SHOULD)。
あるストリームに対して最初に報告されたストリームエラーは、そのストリームにおける他のエラーが報告されることを防ぎます。これに対し、このプロトコルは複数の GOAWAY フレームを許可しますが、エンドポイントは緩やかなシャットダウン中にエラーが発生しない限り、1つの種類のコネクションエラーのみを報告するべきです (SHOULD)。緩やかなシャットダウン中にエラーが発生した場合、エンドポイントは NO_ERROR を含む以前の GOAWAY に加えて、新しいエラーコードと共に追加の GOAWAY フレームを送信してもよいものとします (MAY)。
エンドポイントが複数の異なるエラーを検出した場合、それらのエラーのいずれか1つを報告することを選択してもよいものとします (MAY)。フレームがコネクションエラーを発生させる場合、そのエラーは報告されなければなりません (MUST)。加えて、エンドポイントはエラー状態を検出した場合、適用可能な任意のエラーコードを使用してもよいものとします (MAY)。一般的なエラーコード (PROTOCOL_ERROR や INTERNAL_ERROR など) は、特定のエラーコードの代わりに常に使用できます。
コネクションエラーとは、フレーム層の処理の妨げとなるエラーや、接続状態を破壊するエラーです。
コネクションエラーが発生したエンドポイントは、ピアから受信に成功した最後のストリームIDと共に GOAWAY フレーム (6.8節) を最初に送信するべきです (SHOULD)。GOAWAY フレームにはコネクションが終了した理由を示すエラーコード (7章)が含まれます。エラー状態での GOAWAY フレームの送信後は、エンドポイントは TCP 接続を終了しなければなりません (MUST)。
GOAWAY は受信側エンドポイントで期待通りに受信できない可能性があります。コネクションエラーが発生した場合、GOAWAY はコネクションが終了した理由をベストエフォートでピアに対して伝えるだけです。
エンドポイントはいつでもコネクションを終了することができます。特にエンドポイントは、ストリームエラーをコネクションエラーとして扱えます (MAY)。状況が許す限り、エンドポイントはコネクションを終了するときに GOAWAY フレームを送信するべきです (SHOULD)。
ストリームエラーは、他のストリームの処理には影響しない、特定のストリームに関連するエラーです。
ストリームエラーを検知したエンドポイントは、エラーが発生したストリームのストリームIDを含む RST_STREAM フレーム (6.4節) を送信します。また、RST_STREAM フレームはエラーの種類を示すエラーコードも含みます。
RST_STREAM は、エンドポイントがそのストリーム上で送信できる最後のフレームです。RST_STREAM を送信するピアは、リモートピアによってすでに送信されたフレーム、または送信のためにキューに入れられたどんなフレームも受信する準備をしなければなりません (MUST)。これらのフレームは、接続状態を変更する (フィールドセクション圧縮 (4.3節) やフロー制御の維持に必要な) フレームを除いて、無視できます。
通常、エンドポイントは任意のストリームに対して複数の RST_STREAM フレームを送信するべきではありません (SHOULD NOT)。しかしながら、往復遅延時間が経過した後に終了したストリームに対してフレームを受信した場合には、追加の RST_STREAM フレームを送信してもよいものとします (MAY)。この振る舞いは、不正な実装に対処するために認められます。
ループを防ぐために、エンドポイントは RST_STREAM フレームの応答に RST_STREAM フレームを送信してはいけません (MUST NOT)。
ストリームが "open" または "half-closed" 状態の間に TCP 接続が終了または初期化された場合、その影響を受けたストリームを自動的に再試行することはできません (8.7節)。
HTTP/2 はプロトコルの拡張を認めています。この節で説明する制限の範囲内であれば、プロトコル拡張を追加のサービスの提供やプロトコルの様々な面を変更するために使用できます。拡張は単一の HTTP/2 コネクションの範囲に影響します。
これは、この文書で定義されるプロトコルの要素に適用されます。また、新しいメソッドの定義やステータスコード、フィールド ([HTTP] の16章を参照) といった HTTP を拡張するための既存のオプションには影響しません。
拡張では、新しいフレームタイプ (4.1節)、新しい設定 (6.5節)、新しいエラーコード (7章) の使用が認められています。これらの拡張ポイントを管理するレジストリは [RFC7540]の11章で定義されています。
実装は、全てのプロトコルの拡張要素における不明また未対応の値を無視しなければなりません (MUST)。実装は不明または未対応のタイプのフレームを破棄しなければなりません (MUST)。これはどの拡張ポイントも、事前の合意やネゴシエートなしに拡張によって安全に使用できることを意味します。しかしながら、フィールドブロック (4.3節) の間に現れる拡張フレームは許可されません。これらは PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱われなければなりません (MUST)。
拡張はこの文書に定義されるプロトコルの要素や、拡張メカニズムが定義されていない要素の変更を避けるべきです (SHOULD)。これにはフレームのレイアウトの変更や、フレームを HTTP メッセージに合成する方法の追加や変更 (8.1節)、擬似ヘッダーフィールドの定義、準拠したエンドポイントがコネクションエラー (5.4.1節) として扱うかもしれないあらゆるプロトコルの要素の変更が含まれます。
既存のプロトコルの要素や状態を変更する拡張は、使用される前にネゴシエートされなければなりません (MUST)。例えば、HEADERS フレームの配置を変更する拡張は、ピアからこれを受け入れる肯定的な通知があるまで使用することはできません。このような場合、レイアウトの変更が有効になった時に調整を必要とする可能性があります。例えば、DATA フレーム以外のフレームをフロー制御の対象として扱う場合は、両方のエンドポイントの解釈を要するセマンティクスの変更が必要となり、これはネゴシエーションを通じてのみ完了できます。
この文書では、拡張の使用をネゴシエートする具体的な方法を強制しません。しかし、設定 (6.5.2節) がこのような目的で使用されることに注意してください。もし両方のピアが拡張を使用する意図を示す値を設定した場合は、その拡張は使用されます。拡張のネゴシエーションに設定が使用される場合、その初期値はその拡張が無効になるように定義されなければなりません (MUST)。
この仕様では、一意な8ビットのタイプコードで識別されるいくつかのフレームタイプを定義します。各フレームタイプは、コネクション全体や個々のストリームの確立と管理について、それぞれ異なる目的を果たします。
特定のフレームタイプの送信は、コネクションの状態を変更できます。エンドポイントの両方が接続状態を同期し続けることに失敗した場合、そのコネクションにおいてこれ以上正常な通信をすることはできません。したがって、エンドポイントは特定のフレームを使用することで、状態にどのような影響を与えるかの共通理解を持つことが重要です。
DATA フレーム (type=0x00) は、ストリームに関連する任意の可変長オクテット列を転送します。1個以上の DATA フレームは、HTTP リクエストやレスポンスのメッセージの内容を転送するために使用されます。
DATA フレームは任意のパディングを含んでもよいものとします (MAY)。パディングは DATA フレームのメッセージサイズを隠すために追加できます。パディングはセキュリティのための機能です。詳細は10.7節を参照してください。
DATA Frame { Length (24), Type (8) = 0x00, Unused Flags (4), PADDED Flag (1), Unused Flags (2), END_STREAM Flag (1), Reserved (1), Stream Identifier (31), [Pad Length (8)], Data (..), Padding (..2040), } 図3: DATA フレームフォーマット
Length、Type、Unused Flags、Reserved そして Stream Identifier フィールドは4章で説明した通りです。DATA フレームは以下の追加フィールドを含みます:
DATA フレームは以下のフラグを定義します:
DATA フレームはストリームに関連付けられなければなりません (MUST)。Stream Identifier フィールドが 0x00 の DATA フレームを受信した場合、受信者は PROTOCOL_ERROR のコネクションエラー (5.4.1節) で応答しなければなりません (MUST)。
DATA フレームはフロー制御の対象となり、ストリームが "open" または "half-closed (remote)" 状態の問にのみ送信できます。Pad Length や Padding フィールドが存在する場合は、それらを含む DATA フレームのペイロードの全てが、フロー制御に含まれます。"open" または "half-closed (local)" 状態にないストリームから DATA フレームを受信した場合は、受信者は STREAM_CLOSED のストリームエラー (5.4.2節) で応答しなければなりません (MUST)。
パディングオクテットの合計は、Pad Length フィールドの値により決定されます。パディングの長さが、フレームペイロードの長さと同じかそれよりも大きい場合、受信者は PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。
注: 値が0の Pad Length フィールドを含めることで、フレームを1オクテット大きくできます。
HEADERS フレーム (type=0x01) はストリーム (5.1節) を開くのに使われ、さらにフィールドブロックフラグメントを転送します。名前に反して、HEADERS フレームはヘッダーセクションとトレイラーセクションを転送できます。HEADERS フレームは "idle"、"reserved (local)"、"open" または "half-closed (remote)" 状態のストリームに送信できます。
HEADERS Frame { Length (24), Type (8) = 0x01, Unused Flags (2), PRIORITY Flag (1), Unused Flag (1), PADDED Flag (1), END_HEADERS Flag (1), Unused Flag (1), END_STREAM Flag (1), Reserved (1), Stream Identifier (31), [Pad Length (8)], [Exclusive (1)], [Stream Dependency (31)], [Weight (8)], Field Block Fragment (..), Padding (..2040), } 図4: HEADERS フレームフォーマット
Length、Type、Unused Flags、Reserved そして Stream Identifier フィールドは4章で説明した通りです。HEADERS フレームのペイロードは以下の追加フィールドを持ちます:
HEADERS フレームは以下のフラグを定義します:
HEADERS フレームのペイロードはフィールドブロックフラグメント (4.3節) を含みます。HEADERS フレームに収まらないフィールドブロックは CONTINUATION フレーム (6.10節) として続きます。
HEADERS フレームはストリームに関連付けられなければなりません (MUST)。受信した HEADERS フレームの Stream Identifier フィールドが 0x00 であった場合、受信者は PROTOCOL_ERROR のコネクションエラー (5.4.1節) として応答しなければなりません (MUST)。
HEADERS フレームは、4.3節で定義されたように接続状態を変更します。
パディングオクテットの合計は、Pad Length フィールドの値により決定されます。パディングの長さが、フレームペイロードの長さと同じかそれよりも大きい場合、受信者は PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。
注: 値が 0 の Pad Length フィールドを含めることで、フレームを1オクテット大きくできます。
PRIORITY フレーム (type=0x02) は非推奨です (5.2.3節を参照)。PRIORITY フレームは idle や closed のストリームを含む、全ての状態のストリームに送信できます。
PRIORITY Frame { Length (24) = 0x05, Type (8) = 0x02, Unused Flags (8), Reserved (1), Stream Identifier (31), Exclusive (1), Stream Dependency (31), Weight (8), } 図5: PRIORITY フレームフォーマット
Length、Type、Unused Flags、Reserved そして Stream Identifier フィールドは4章で説明した通りです。PRIORITY フレームのペイロードは以下の追加フィールドを持ちます:
PRIORITY フレームはフラグを定義しません。
PRIORITY フレームは常にストリームに関連付けられます。ストリームIDが 0x00 の PRIORITY フレームを受信した場合、受信者は PROTOCOL_ERROR のコネクションエラー (5.4.1節) として応答しなければなりません (MUST)。
PRIORITY フレームの送信や受信はストリームの状態に影響を与えません (5.1節)。PRIORITY フレームは "idle" や "closed" 状態を含む全ての状態のストリームに送信できます。PRIORITY フレームは、1つのフィールドブロックを構成する連続したフレームの間には送信できません (4.3節)。
長さが5オクテットでない PRIORITY フレームは、FRAME_SIZE_ERROR のストリームエラー (5.4.2節) として扱われなければなりません (MUST)。
RST_STREAM フレーム (type=0x03) はストリームの即時終了を可能にします。RST_STREAM はストリームのキャンセルの要求やエラーの状態にあることを示すために送信されます。
RST_STREAM Frame { Length (24) = 0x04, Type (8) = 0x03, Unused Flags (8), Reserved (1), Stream Identifier (31), Error Code (32), } 図6: RST_STREAM フレームフォーマット
Length、Type、Unused Flags、Reserved そして Stream Identifier フィールドは4章で説明した通りです。さらに、RST_STREAM フレームはエラーコード (7章) を特定する符号なし32ビット整数を1つ含みます。このエラーコードは、ストリームが終了する理由を示します。
RST_STREAM フレームはフラグを定義しません。
RST_STREAM フレームは関連するストリームを完全に終了し、"closed" 状態に遷移させます。RST_STREAM をストリーム上で受信した後に、受信者はそのストリームに対して PRIORITY 以外の追加のフレームを送信してはいけません (MUST NOT)。しかしながら、RST_STREAM を送信した後でも、送信側エンドポイントは、RST_STREAM が到着する前にピアが 送信したかもしれない追加のフレームを受信し、処理する準備をしなければなりません (MUST)。
RST_STREAM フレームはストリームに関連付けられなければなりません (MUST)。受信した RST_STREAM フレームの Stream Identifier フィールドが 0x00 であった場合、受信者は PROTOCOL_ERROR のコネクションエラー (5.4.1節) として応答しなければなりません (MUST)。
RST_STREAM フレームは "idle" 状態のストリームに送信してはいけません (MUST NOT)。"idle" 状態のストリームに関連する RST_STREAM フレームを受信した場合は、受信者は PROTOCOL_ERROR のコネクションエラー (5.4.1節) として応答しなければなりません (MUST)。
長さが 4 オクテットでない RST_STREAM フレームは、FRAME_SIZE_ERROR のコネクションエラー (5.4.1節) として扱われなければなりません (MUST)。
SETTINGS frame (type=0x04) は、ピアの振る舞いに関する初期設定や制約といった、エンドポイントの通信方法に影響を与える設定パラメーターを転送します。SETTINGS フレームはそのような設定の受信確認にも使用されます。SETTINGS フレームに含まれる設定パラメーターを個別に「設定」と呼びます。
設定はネゴシエートされません。これらは送信側ピアが特性を記述し、受信側ピアによって使用されます。また、それぞれのピアから、同一の設定に対して異なる値が通知されます。例えば、クライアントは高い初期フロー制御ウインドウを設定するかもしれませんが、サーバーはリソースを節約するために低い値を設定するかもしれません。
SETTINGS フレームは、コネクション開始時に両方のエンドポイントから送信されなければなりません (MUST)。また、接続中はいかなる時でもいずれかのエンドポイントから送信してもよいものとします (MAY)。実装は、この仕様に定義されている全ての設定に対応しなければなりません (MUST)。
SETTINGS フレームの各パラメーターは、その設定の既存の値を置き換えます。パラメーターは登場した順序で処理され、SETTINGS フレームの受信者は現在の設定値以外の状態を維持する必要はありません。したがって SETTINGS パラメーターの値は受信者が最後に処理した値になります。
SETTINGS フレームは受信したピアにより確認されます。これを可能にするため、SETTINGS フレームは ACK フラグを定義します:
SETTINGS フレームは、1つのストリームではなく、コネクションに対して常に適用されます。SETTINGS フレームのストリームIDは 0 (0x00) でなければなりません (MUST)。Stream Identifier フィールドに 0x00 以外の値が設定された SETTINGS フレームを受信した場合、エンドポイントは PROTOCOL_ERROR のコネクションエラー (5.4.1節) として応答しなければなりません (MUST)。
SETTINGS フレームは接続状態に影響します。不正な形式や不完全な SETTINGS フレームは、PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱われなければなりません (MUST)。
長さが6オクテットの倍数でない SETTINGS フレームは、FRAME_SIZE_ERROR のコネクションエラー (5.4.1節) として扱われなければなりません (MUST)。
SETTINGS フレームのフレームペイロードは0個以上の設定からなり、各設定は16ビットの設定識別子と符号なし32ビットの値で構成されます。
SETTINGS Frame { Length (24), Type (8) = 0x04, Unused Flags (7), ACK Flag (1), Reserved (1), Stream Identifier (31) = 0, Setting (48) ..., } Setting { Identifier (16), Value (32), } 図7: SETTINGS フレームフォーマット
Length、Type、Unused Flags、Reserved そして Stream Identifier フィールドは4章で説明した通りです。SETTINGS フレームのフレームペイロードは任意の数の Setting フィールドを含み、各フィールドは次のように構成されます:
定義済みの設定は次の通りです:
不明や未対応の識別子を含む SETTINGS フレームを受信したエンドポイントは、その設定を無視しなければなりません (MUST)。
SETTINGS のほとんどの値は、ピアがいつ変更されたパラメーターの値を受信してその値を適用したかを把握することが有効であるか、または必要とします。このような同期点を提供するために、ACK フラグが設定されていない SETTINGS フレームの受信者は、受信後に更新された設定を可能な限り早く適用しなければなりません (MUST)。SETTINGS フレームは受信した順序で応答されます。
SETTINGS フレームの値は、その間に他のフレームを処理することなく、出現した順序で処理されなければなりません (MUST)。未対応の設定は無視されなければなりません (MUST)。全ての値を処理後、受信者は ACK フラグを設定した SETTINGS フレームを直ちに送信しなければなりません (MUST)。ACK フラグが設定された SETTINGS フレームを受信すると、変更した設定の送信者は確認されていない最も古い SETTINGS フレームの値が適用されていると見なすことができます。
SETTINGS フレームの送信者が妥当な時間内に応答を受信しなかった場合、SETTINGS_TIMEOUT のコネクションエラー (5.4.1節) として応答してもよいものとします (MAY)。タイムアウトの設定時には、ピアでの処理遅延時間を考慮する必要があります。エンドポイント間の往復遅延時間のみに基づくタイムアウトは、誤ったエラーを引き起こす可能性があります。
PUSH_PROMISE フレーム (type=0x05) は、送信者が開始する予定のストリームを事前にピアエンドポイントに通知するために使用します。PUSH_PROMISE フレームは、エンドポイントがストリームに追加のコンテキストを提供するフィールドセクションと共に、作成する予定のストリームの符号なし31ビット識別子を含みます。PUSH_PROMISE フレームの使用についての完全な説明は、8.4節に記述されています。
PUSH_PROMISE Frame { Length (24), Type (8) = 0x05, Unused Flags (4), PADDED Flag (1), END_HEADERS Flag (1), Unused Flags (2), Reserved (1), Stream Identifier (31), [Pad Length (8)], Reserved (1), Promised Stream ID (31), Field Block Fragment (..), Padding (..2040), } 図8: PUSH_PROMISE フレームフォーマット
Length、Type、Unused Flags、Reserved そして Stream Identifier フィールドは4章で説明した通りです。PUSH_PROMISE フレームペイロードは、以下の追加フィールドを含みます:
PUSH_PROMISE フレームは以下のフラグを定義します:
PUSH_PROMISE フレームは、"open" または "half-closed (remote)" 状態の、ピアにより開始されたストリームでのみ送信されなければなりません (MUST)。PUSH_PROMISE フレームのストリームIDは、そのストリームが関連付けられたものであることを示します。Stream Identifier フィールドに 0x00 を指定した場合、受信者は PROTOCOL_ERROR のコネクションエラー (5.4.1節) として応答しなければなりません (MUST)。
予約済みストリームは、それらが予約された順番で使用される必要はありません。PUSH_PROMISE は今後使用するストリームIDのみを予約します。
ピアエンドポイントの SETTINGS_ENABLE_PUSH 設定に0が設定された場合は、PUSH_PROMISE は送信されてはいけません (MUST NOT)。SETTINGS_ENABLE_PUSH 設定を0に設定し、その応答を受信したエンドポイントは、PUSH_PROMISE フレームの受信を PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。
PUSH_PROMISE フレームの受信者は、PUSH_PROMISE の送信者に予約済みストリームIDを参照する RST_STREAM を送信することで、予約済みストリームを拒否できます。
PUSH_PROMISE フレームは2つの方法で接続状態を変更します。フィールドブロック (4.3節)を含めることは、フィールドセクション圧縮のために保持されている状態を変更する可能性があります。PUSH_PROMISE は、予約済みストリームを "reserved (local)" や "reserved (remote)" 状態に遷移させることで、今後使用するストリームを予約します。送信者は、"open" または "half-closed (remote)" のいずれかの状態ではないストリームには PUSH_PROMISE を送信してはいけません (MUST NOT)。また、送信者は予約済みストリームが新しいストリームID (5.1.1節) を正しく選択していることも保証しなければなりません (MUST) (これはつまり、予約済みストリームは "idle" 状態でなければなりません (MUST))。
PUSH_PROMISE はストリームを予約するため、PUSH_PROMISE フレームを無視することは、ストリームの状態を不安定にさせる原因となります。受信者は "open" や "half-closed (local)" でないストリームでの PUSH_PROMISE への応答は、PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。しかしながら、関連付けられたストリームで RST_STREAM を送信したエンドポイントは、RST_STREAM フレームが受信または処理される前に生成された可能性のある PUSH_PROMISE フレームを扱わなければなりません (MUST)。
受信者は不正なストリームID (5.1.1節) を予約する PUSH_PROMISE への応答を、PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。不正なストリームIDは、現在 "idle" 状態ではないストリームのIDを指すことに注意してください。
パディングオクテットの合計は、Pad Length フィールドの値により決定されます。パディングの長さが、フレームペイロードの長さと同じかそれよりも大きい場合、受信者は PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。
注: 値が 0 の Pad Length フィールドを含めることで、フレームを1オクテット大きくできます。
PING フレーム (type=0x06) は、送信者からの最小往復遅延時間を計測し、アイドル状態のコネクションがまだ機能しているかどうかを判断するするための仕組みです。PING フレームはどちらのエンドポイントからもも送信できます。
PING Frame { Length (24) = 0x08, Type (8) = 0x06, Unused Flags (7), ACK Flag (1), Reserved (1), Stream Identifier (31) = 0, Opaque Data (64), } 図9: PING フレームフォーマット
Length、Type、Unused Flags、Reserved そして Stream Identifier フィールドは4章で説明した通りです。
PING フレームは、フレームヘッダーに加え、フレームペイロードに8オクテットの Opaque データを含まなければなりません (MUST)。送信者は選択した任意の値を含めることができ、それらのオクテットは任意の方法で使用できます。
ACK フラグを含まない PING フレームの受信者は、そのレスポンスとして同じフレームペイロードと共に ACK フラグを設定した PING フレームを送信しなければなりません (MUST)。PING レスポンスは他のフレームよりも高い優先度が設定されるべきです (SHOULD)。
PING フレームは以下のフラグを定義します:
PING フレームは個別のストリームには関連付けられません。Stream Identifier フィールドの値が 0x00 でない PING フレームを受信した場合、受信者は PROTOCOL_ERROR のコネクションエラー (5.4.1節) として応答しなければなりません (MUST)。
長さフィールドの値が 8 になっていない PING フレームの受信者は、FRAME_SIZE_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。
GOAWAY フレーム (type=0x07) はコネクションの終了の開始や、重大なエラー状態の通知に使用されます。GOAWAY はエンドポイントが以前に確立されたストリームの処理を完了している間に、新しいストリームの受け入れを緩やかに停止できるようにします。これにより、サーバーメンテナンスのような管理作業を可能にします。
新しくストリームを開始したエンドポイントと、GOAWAY フレームを送信したリモートピアの間には、固有の競合状態があります。このような場合に対処するため、GOAWAY は現在のコネクションで送信側エンドポイントが最後に処理した、または処理された可能性のある、ピアが開始した最後のストリームIDを含みます。例えば、サーバーが GOAWAY フレームを送信した場合、最後のストリームIDは、クライアントが開始したストリームの最も大きい番号のストリームIDになります。
GOAWSY が送信されると、送信者は、最終ストリームIDに指定した値よりも大きいストリームIDをもつ、新しいストリームに送信されたフレームを無視します。GOAWAY フレームの受信者は、現在のコネクション上で新しい追加のストリームを開始してはいけません (MUST NOT)。しかし、新しいストリームを生成するために新しくコネクションを確立できます。
GOAWAY の受信者が、GOAWAY フレームで示されたストリームIDよりも大きいIDを持つストリームにデータを送信した場合、それらのストリームは処理されません。GOAWAY フレームの受信者は、そのストリームの全てが生成されなかったものとして扱うことができます。したがって、これらのストリームは、後に新しいコネクション上で再施行できます。
ストリームが部分的に処理されたのかどうかを、リモートピアが知ることができるよう、エンドポイントはコネクションを終了する前に、常に GOAWAY フレームを送信するべきです (SHOULD)。例えば、ある HTTP クライアントが、サーバーがコネクションを終了するのと同時に POST を送信した場合に、サーバーがどのストリームまで処理したかを示す GOAWAY フレームを送信しなければ、クライアントはサーバーが POST リクエストの処理を開始したのかどうかを知ることができません。
不正なピアに対しては、エンドポイントは GOAWAY の送信なしにコネクションを終了することを選ぶかもしれません。
GOAWAY フレームは直ちにコネクションの終了を開始しない可能性があります。コネクションをこれ以上使用しない GOAWAY の受信者であっても、コネクションを終了する前に GOAWAY フレームを送信するべきです (SHOULD)。
GOAWAY Frame { Length (24), Type (8) = 0x07, Unused Flags (8), Reserved (1), Stream Identifier (31) = 0, Reserved (1), Last-Stream-ID (31), Error Code (32), Additional Debug Data (..), } 図10: GOAWAY フレームフォーマット
GOAWAY フレームはフラグを定義しません。
GOAWAY フレームは特定のストリームではなく、コネクションに対して適用されます。エンドポイントはストリームIDが 0x00 以外の値になっている GOAWAY フレームを PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。
GOAWAY の最終ストリームIDには、GOAWAY フレームの送信者が何らかの動作をおこなった、あるいはまだ動作をおこなっていないストリームのうち、最も大きい値のストリームIDが含まれます。このストリームIDまでのストリームは全て、すでに何らかの方法で処理された可能性があります。処理されたストリームが存在しない場合は、最終ストリームIDに0が設定される可能性があります。
注: この文脈における "処理された" とはストリームのデータが、何らかの動作をするかもしれない上位層のソフトウェアに渡された結果を意味します。
GOAWAY フレームの送信なしにコネクションを終了した場合、最終ストリームIDは事実上もっとも大きい値のストリームIDになります。
指定された値と等しいまたはそれ以下のIDを持つストリームのうち、コネクションが終了する前に完全に終了されていないストリームでは、リクエストの再試行やトランザクション、HTTP GET、PUT、DELETE のような冪等な動作を除く、その他のプロトコル処理ができません。指定された値よりも大きいIDのストリームを使用するプロトコル処理は、新しいコネクションを使用して安全に再実行できます。
最終ストリームIDの値と等しいかまたはそれ以下のIDを持つストリームでの処理は、正常に完了する可能性があります。GOAWAY フレームの送信者は、処理中のストリームが全て完了するまで "open" 状態でコネクションを維持し、GOAWAY フレームを送信することで緩やかにコネクションを終了するかもしれません。
状況の変化に応じて、エンドポイントは複数の GOAWAY フレームを送信してもよいものとします (MAY)。例えば、緩やかなシャットダウン中に NO_ERROR と共に GOAWAY を送信したエンドポイントは、その後、接続の即時終了を必要とする状況に陥る可能性があります。受信した最後の GOAWAY フレームの最終ストリームIDは、処理した可能性があるストリームを示します。エンドポイントは、ピアが既に別のコネクション上で未処理リクエストの再施行をしている可能性があるため、自身が送信した最終ストリームIDの値を大きくしてはいけません (MUST NOT)。
リクエストを再施行できないクライアントは、サーバーがコネクションを終了すると、転送中の全てのリクエストを失うことになります。これは、HTTP/2 を使用してクライアントにサービスを提供していない可能性のある中継者にとっては特に起こりえます。コネクションの緩やかなシャットダウンを試みるサーバーは、最終ストリームIDに 2^31-1 を設定し、NO_ERROR コードを設定した最初の GOAWAY フレームを送信すべきです (SHOULD)。これは、シャットダウンが近づいており、さらなるリクエストの開始は禁止されていることをクライアントに通知します。送信中のストリーム生成のための時間 (少なくとも1回分の往復遅延時間) を与えた後、サーバーは更新された最終ストリームIDと共に再度 GOAWAY フレームを送信してもよいものとします (MAY)。これにより、リクエストを失うことなく、正しくコネクションが終了されることを確実にします。
GOAWAY フレームの送信後、送信者は受信者により送信された最終ストリームに指定したIDよりも大きいIDを持つストリームのフレームを破棄することができます。しかしながら、接続状態を変更するフレームは完全には無視されません。例えば、HEADERS、PUSH_PROMISE、CONTINUATION フレームは、矛盾のないフィールドセクション圧縮の状態 (4.3節) を保証するために、最低限処理されなければなりません (MUST)。同様に、DATA フレームはコネクションフロー制御ウインドウに対して計算されなければなりません (MUST)。これらのフレームの処理に失敗すると、フロー制御やフィールドセクション圧縮の状態が同期されない可能性があります。
GOAWAY フレームは、コネクションを終了する理由を示す32ビットのエラーコード (7章) も含みます。
エンドポイントは、GOAWAY フレームのフレームペイロードに未定義のデータを追加してもよいものとします (MAY)。デバッグ情報にはセキュリティやプライバシーに関わるデータを含めることができます。記録されていたり、永続的に格納されているデバッグデータは、不正なアクセスを防ぐために適切な保護手段を持たなければなりません (MUST)。
WINDOW_UPDATE フレーム (type=0x08) フロー制御を実装するために使用されます。概要については5.2節を参照してください。
フロー制御は、個々のストリームとコネクション全体の2段階でおこなわれます。
どちらの段階のフロー制御もホップ間、つまり2つのエンドポイントの間でのみおこなわれます。中継者は繋がっているコネクションの間で WINDOW_UPDATE フレームを転送しません。しかしながら受信者がデータ転送をスロットリングすることによって、元の送信者に対してフロー制御情報を間接的に伝搬させることができます。
フロー制御は、フロー制御の対象となる特定のフレームにのみ適用されます。この文書に定義されるフレームの種類のうち、対象となるのは DATA フレームのみです。フロー制御の対象でないフレームは、受信者がフレームを処理するためのリソースの割り当てに失敗しない限り、受け入れ、処理されなければなりません (MUST)。フレームの受け入れに失敗した場合、受信者はストリームエラー (5.4.2節) または FLOW_CONTROL_ERROR のコネクションエラー (5.4.1節) として応答してもよいものとします (MAY)。
WINDOW_UPDATE Frame { Length (24) = 0x04, Type (8) = 0x08, Unused Flags (8), Reserved (1), Stream Identifier (31), Reserved (1), Window Size Increment (31), } 図11: WINDOW_UPDATE フレームフォーマット
Length、Type、Unused Flags、Reserved そして Stream Identifier フィールドは4章で説明した通りです。WINDOW_UPDATE フレームのフレームペイロードは、1つの予約ビットと、既存のフロー制御ウインドウに加えて送信者が送信可能なオクテット数を示す、符号なし31ビットの整数からなります。フロー制御ウインドウの増加量として認められる範囲は、1 から 2^31-1 (2,147,483,647) オクテットです。
WINDOW_UPDATE フレームはフラグを定義しません。
WINDOW_UPDATE フレームは、ストリームやコネクションを特定できます。ストリームの場合、フレームのストリームIDが対象のストリームを示し、コネクションの場合は、ストリームID "0" がこのフレームの対象がコネクション全体であることを示します。
受信者は、フロー制御ウインドウの増加量に 0 が指定された WINDOW_UPDATE フレームの受信を、PROTOCOL_ERROR のストリームエラー (5.4.2節) として扱わなければなりません (MUST)。コネクションフロー制御ウインドウでの同様のエラーは、コネクションエラー (5.4.1節) として扱わなければなりません。
WINDOW_UPDATE は、END_STREAM フラグを設定したフレームを送信したピアから送信されることがあります。これは、受信者が "half-closed (remote)" や "closed" 状態のストリームで WINDOW_UPDATE フレームを受信する可能性があることを意味します。受信者はこれをエラーとして扱ってはいけません (MUST NOT) (5.1節を参照)。
フロー制御下のフレームを受信した受信者は、受信者がコネクションエラー (5.4.1節)として扱わない限り、常にコネクションフロー制御ウインドウへの影響を考慮しなければなりません (MUST)。この考慮はフレームにエラーがある場合であっても必要です。送信者はフロー制御ウィンドウに対してフレームを計算しているため、受信者がこれをおこなわなければ、送信者と受信者のフロー制御ウインドウに差異が発生する可能性があります。
長さが4オクテットでない WINDOW_UPDATE フレームは、FRAME_SIZE_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。
HTTP/2 におけるフロー制御は、各ストリームの送信者ごとに保持されるウインドウを使用することで実装されます。フロー制御ウインドウは、送信者が送信可能なデータのオクテット数を示す、シンプルな整数値です。このサイズは、受信者のバッファ容量を計測したサイズでもあります。
ストリームフロー制御ウインドウと、コネクションフロー制御ウインドウの2つのフロー制御ウインドウが適用されます。送信者は、受信者から告知されたいずれかのフロー制御ウインドウで、使用可能な容量を超える長さのフロー制御下にあるフレームを送信してはいけません (MUST NOT)。いずれかのフロー制御ウインドウに使用可能な容量がない場合は、END_STREAM フラグが設定された長さが 0 のフレーム (つまり、空の DATA フレーム) を送信してもよいものとします (MAY)。
フロー制御の計算対象には、9オクテットのフレームヘッダーは含まれません。
フロー制御下のフレームを送信後、送信者は2つのウインドウの使用可能な容量から、送信したフレームの長さ分を減少させます。
フレームの受信者はデータを処理し、フロー制御ウインドウの領域を開放すると、WINDOW_UPDATE フレームを送信します。ストリームレベルとコネクションレベルのそれぞれのフロー制御ウインドウに対して、それぞれの WINDOW_UPDATE フレームが送信されます。受信者は非常に小さな容量で WINDOW_UPDATE フレームを送信しないようにする仕組みを持つことが推奨されます ([RFC1112] の4.2.3.3節を参照)。
WINDOW_UPDATE フレームを受信した送信者は、フレームに指定された容量を使用して、関連するウインドウを更新します。
送信者は、2^31-1 オクテットを超えるフロー制御ウインドウを許可してはいけません (MUST NOT)。送信者がこの最大容量を超えるフロー制御ウインドウが指定された WINDOW_UPDATE を受信した場合は、ストリームまたはコネクションのいずれか適切な方を終了しなければなりません (MUST)。ストリームにおいては FLOW_CONTROL_ERROR のエラーコードと共に RST_STREAM を、コネクションにおいては FLOW_CONTROL_ERROR のエラーコードと共に GOAWAY フレームを送信者は送信します。
送信者からのフロー制御下のフレームと、受信者からの WINDOW_UPDATE フレームは、お互いに完全に非同期です。この特性は、ストリームが停止するのを防ぎ、送信者が保持するウインドウサイズを受信者が積極的に更新することを可能にします。
HTTP/2 接続が最初に確立された時に、65,535 オクテットの初期フロー制御ウインドウサイズと共に新しいストリームが作成されます。コネクションフロー制御ウインドウも 65,535 オクテットになります。どちらのエンドポイントも SETTINGS フレームに SETTINGS_INITIAL_WINDOW_SIZE の値を含めることで、新しいストリームの初期ウインドウサイズを調整できます。コネクションフロー制御ウインドウは WINDOW_UPDATE フレームを使用してのみ変更できます。
SETTINGS_INITIAL_WINDOW_SIZE の値が設定された SETTINGS フレームを受信する前に、フロー制御下のフレームを送信する場合は、エンドポイントはデフォルトの初期ウインドウサイズのみを使用できます。同様に、WINDOW_UPDATE フレームを受信するまでは、コネクションフロー制御ウインドウにはデフォルトの初期ウインドウサイズに基づいて設定されます。
まだアクティブではないストリームのフロー制御ウインドウの変更に加えて、SETTINGS フレームはアクティブなフロー制御ウインドウを持つストリーム (つまり、"open" または "half-closed (remote)" の状態にあるストリーム) の初期フロー制御ウインドウを変更できます。SETTINGS_INITIAL_WINDOW_SIZE の値が変更された時は、受信者は新しい値と古い値の差分を維持し、全てのストリームのフロー制御ウインドウサイズを調整しなければなりません (MUST)。
SETTINGS_INITIAL_WINDOW_SIZE の変更は、フロー制御ウインドウの使用可能な容量を負の値にする可能性があります。送信者は負の値のフロー制御ウインドウに従わなければならず (MUST)、フロー制御ウインドウが正の値になる WINDOW_UPDATE フレームを受信するまで、新しいフロー制御下のフレームを送信してはいけません (MUST NOT)。
例えば、クライアントがコネクション確立と同時に 60KB を送信し、サーバーが初期ウインドウサイズを 16KB に設定した場合、クライアントは SETTINGS フレームの受信時に、使用可能なフロー制御ウインドウを -44KB に再計算します。クライアントは、WINDOW_UPDATE フレームがウインドウを正の値に戻すまで、負の値のフロー制御ウインドウを保持します。ウインドウが正の値に戻った後に、クライアントは送信を再開します。
SETTINGS フレームはコネクションフロー制御ウインドウを変更できません。
エンドポイントは、フロー制御ウインドウが最大サイズを超えるような SETTINGS_INITIAL_WINDOW_SIZE の変更を FLOW_CONTROL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。
現在のサイズよりも少ないフロー制御ウインドウの使用を要求する受信者は、新しい SETTINGS フレームを送信できます。しかしながら、送信者は SETTINGS フレームを処理する前に、変更後の制限を超えるデータを送信した可能性があるため、受信者は変更後のウインドウサイズを超えるデータの受信に備えなければなりません (MUST)。
初期フロー制御ウインドウサイズを減少させる SETTINGS フレームの送信後、受信者はフロー制御の制限を超えるストリームの処理を続けてもよいものとします (MAY)。ストリームの続行を可能にすることは、フロー制御ウインドウのために確保された空間を直ちに減らすことを受信者に認めるものではありません。送信者に対して送信再開を許可するために WINDOW_UPDATE フレームが必要になるまで、これらのストリームの処理は停止できます。受信者は影響を受けたストリームに対して、FLOW_CONTROL_ERROR エラーと共に RST_STREAM を代わりに送信してもよいものとします (MAY)。
CONTINUATION フレーム (type=0x09) は連続するフィールドブロックフラグメントの続きに使用されます (4.3節)。同一ストリームの直前のフレームが END_HEADERS が設定されていない HEADERS、PUSH_PROMISE、または CONTINUATION である限り、任意の数の CONTINUATION フレームを送信できます。
CONTINUATION Frame { Length (24), Type (8) = 0x09, Unused Flags (5), END_HEADERS Flag (1), Unused Flags (2), Reserved (1), Stream Identifier (31), Field Block Fragment (..), } 図12: CONTINUATION フレームフォーマット
Length、Type、Unused Flags、Reserved そして Stream Identifier フィールドは4章で説明した通りです。CONTINUATION フレームのペイロードはフィールドブロックフラグメントを含みます (4.3節)。
CONTINUATION フレームは以下のフラグを定義します:
CONTINUATION フレームは4.3節で定義されるように接続状態を変更します。
CONTINUATION フレームはストリームに関連付けられなければなりません (MUST)。Stream Identifier フィールドの値が 0x00 になっている CONTINUATION フレームを受信した場合、受信者は PROTOCOL_ERROR のコネクションエラー (5.4.1節) として応答しなければなりません (MUST)。
CONTINUATION フレームは、END_HEADERS フラグが設定されていない HEADERS、PUSH_PROMISE、または CONTINUATION フレームの後に続いてなければなりません (MUST)。このルールへの違反を検知した受信者は、PROTOCOL_ERROR のコネクションエラー (5.4.1節) として応答しなければなりません (MUST)。
エラーコードは、ストリームやコネクションのエラー理由を伝えるために RST_STREAM と GOAWAY フレームで使用される32ビットのフィールドです。
エラーコードは共通のコード領域を共有します。一部のエラーコードは、ストリームまたはコネクション全体のいずれかのみに適用され、それ以外の状況では定義されたセマンティクスを持ちません。
以下のエラーコードが定義されます:
不明または未対応のエラーコードは、特別な反応を引き起こしてはなりません (MUST NOT)。これらは、実装では INTERNAL_ERROR と等価として扱ってもよいものとします (MAY)。
HTTP/2 は HTTP メッセージの抽象概念 ([HTTP] の6章) をインスタンス化したものです。
クライアントは、過去に使用していないストリームID (5.1.1節) を使用して、新しいストリーム上で HTTP リクエストを送信します。サーバーはリクエストと同一のストリーム上で HTTP レスポンスを送信します。
HTTP メッセージ (リクエストやレスポンス) はそれぞれ以下のフレームから成ります:
レスポンスに限り、サーバーは最終的なレスポンスを含む HEADERS フレームの前に任意の数の中間レスポンスを送信してもよいものとします (MAY)。中間レスポンスは、制御データと中間 (1xx) HTTP レスポンスのヘッダーセクション ([HTTP] の15章を参照) を含む HEADERS フレーム (とそれに続く0個以上の CONTINUATION フレーム) で構成されます。END_STREAM フラグが設定された情報提供ステータスコードを転送する HEADERS フレームは不正な形式 (8.1.1節) です。
一連のフレームの最後のフレームは END_STREAM フラグを持ちます。END_STREAM フラグを持つ HEADERS フレームの後には、残りのフィールドブロックのフラグメントを転送する CONTINUATION フレームが続く可能性があることに注意してください。
(任意のストリームの) その他のフレームは、HEADERS フレームとその後に続く可能性のある CONTINUATION フレームの間に存在してはいけません (MUST NOT)。
HTTP/2 はメッセージコンテンツの転送に DATA フレームを使用します。[HTTP/1.1] の7.1節で定義されている chunked 転送エンコーディングは HTTP/2 では使用できません (8.2.2節を参照)
トレイラーフィールドはストリームを終了するフィールドブロックにより転送されます。すなわち、トレイラーフィールドは END_STREAM フラグを持つ HEADERS フレームで始まり、その後に続く0個以上の CONTINUATION フレームで構成されます。トレイラーは擬似ヘッダーフィールド (8.3節) を含んではいけません (MUST NOT)。トレイラーで擬似ヘッダーフィールドを受信したエンドポイントはリクエストやレスポンスを不正な形式 (8.1.1節) として扱わなければなりません (MUST)。
最終的な (情報提供でない) ステータスコードを受信した後に、END_STREAM フラグが設定されていない HEADERS フレームを受信したエンドポイントは、対応するリクエストやレスポンスを不正な形式 (8.1.1節) として扱わなければなりません (MUST)。
HTTP リクエスト/レスポンスの交換は1つのストリームを完全に消費します。リクエストは、ストリームを "open" 状態にする HEADERS フレームで開始されます。そのリクエストは、ストリームをクライアントでは "half-closed (local)" 状態に、サーバーでは "half-closed (remote)" 状態にする END_STREAM フラグが設定されたフレームで終了します。レスポンスストリームは HEADERS フレームに含まれる0個以上の中間レスポンスで始まり、最終的なステータスコードを含む HEADERS フレームが続きます。
HTTP レスポンスは、END_STREAM フラグが設定されたフレーム (フィールドブロックの完成に必要な CONTINUATION フレームを含む) をサーバーが送信、またはクライアントが受信した時に完了します。レスポンスが未送信または未受信のリクエストの一部に依存しない場合、サーバーは、クライアントがリクエストを完全に送信する前に、完全なレスポンスを送信できます。このような場合、サーバーは、完全なレスポンス (例: END_STREAM フラグが設定されたフレーム) の送信後に NO_ERROR のエラーコードと共に RST_STREAM を送信することで、クライアントにリクエストの送信中止を要求してもよいものとします (MAY)。クライアントは、この他の理由においては常に自身の裁量でレスポンスを破棄できますが、このような RST_STREAM を受信した結果としてのレスポンスは破棄してはいけません (MUST NOT)。
不正な形式のリクエストやレスポンスとは、有効な一連の HTTP/2 フレームである一方で、無関係なフレームや禁止されたヘッダーフィールドや擬似ヘッダーフィールド、必須の疑似ヘッダーフィールドの不足、大文字のヘッダーフィールド名の指定、無効なフィールド名や値 (特定の状況下のみ、8.2節を参照) などの理由から無効になるものです。
メッセージコンテンツを持つリクエストやレスポンスは content-length ヘッダーフィールドを含むことができます。メッセージがコンテンツを持たないと定義されない限り、content-length ヘッダーフィールドの値とコンテンツを構成する DATA フレームペイロードの長さの合計が等しくない場合、リクエストやレスポンスは不正な形式になります。例えば、204 や 304 レスポンスは、HEAD リクエストのレスポンスと同様にコンテンツを持ちません。[HTTP] の6.4.1節で述べられているように、コンテンツを持たないと定義されたレスポンスは、DATA フレームに内容が含まれていない場合であっても、値が 0 以外の値の content-length ヘッダーフィールドを持っていてもよいものとします (MAY)。
HTTP のリクエストやレスポンスを処理する中継者 (つまり、トンネルとして機能しない全ての中継者) は、不正な形式のリクエストやレスポンスを転送してはいけません (MUST NOT)。不正な形式のリクエストやレスポンスが検出された場合、PROTOCOL_ERROR のストリームエラー (5.4.2節) として扱わなければなりません (MUST)。
サーバーは不正な形式のリクエストについて、ストリームを終了したり、リセットをする前に HTTP レスポンスを送信してもよいものとします (MAY)。クライアントは不正な形式のレスポンスを受け入れてはいけません (MUST NOT)。
順次メッセージを処理するエンドポイントは、リクエストやレスポンスが不正な形式だと認識する前に何らかの処理をする可能性があります。例えば、完全なリクエストを受信することなく情報提供または 404 ステータスコードを生成することは可能かもしれません。同様に、中継者はエラーを検知する前に不完全なメッセージを転送するかもしれません。サーバーはレスポンスがリクエストの残りの部分の正しさに依存しない場合、リクエスト全体を受信する前に最終的なレスポンスを生成してもよいものとします (MAY)。
これらの要件は、HTTP に対する一部の一般的な攻撃手法からの保護を意図しており、これに寛容であると実装が脆弱性に晒されることにもなるため、意図的に厳格にしています。
HTTP フィールド ([HTTP] の5章) は HTTP/2 では HPACK ([COMPRESSION]) で圧縮され HEADERS、CONTINUATION、そして PUSH_PROMISE フレームで転送されます。
フィールド名は HTTP/2 メッセージを構築する時にフィールド名は小文字に変換されなければなりません (MUST)。
HTTP のフィールド名とその値の定義は、HPACK が転送可能な一部の文字を禁止しています。HTTP/2 の実装は [HTTP] の5.1節と5.5節の定義に従い、フィールド名と値を検証し、禁止された文字を含むメッセージを不正な形式として扱うべきです (SHOULD)。
フィールドの検証の失敗は、リクエストスマグリング攻撃に悪用される可能性があります。特に、キャリッジリターンやラインフィード、コロンなどの文字といった区切りに使用される HTTP/1.1 を使用してメッセージが転送される場合は、検証されていないフィールドが攻撃を可能にするかもしれません。実装は次のような最低限のフィールド名と値の検証をしなければなりません (MUST)。
注: [HTTP] の5.1節と5.5節の定義に従ってフィールドを検証している実装は、フィールド名に大文字が含まれていないことを追加で検証すればよいことになります。
これらのいずれかの条件に違反するフィールドを含むリクエストやレスポンスは不正な形式 (8.1.1節) として扱われなければならない (MUST)。特に、メッセージを転送する際にフィールドを処理しない中継者は、上記で禁止されている値のいずれかを含むフィールドを転送してはいけません (MUST NOT)。
リクエストメッセージがこれらの要件のいずれかに違反した場合、実装はより適切なステータスコードが定義されているか、ステータスコードを送信できない場合 (例: エラーがトレイラーフィールドで発生したため) を除いて、400 (Bad Request) ステータスコード ([HTTP] の15.5.1節を参照) を生成するべきです (SHOULD)。
注: 対応するフィールドの定義に従って有効でないフィールド値は、リクエストを不正とする原因にはなりません。上記の要件は、[HTTP] の5章で定義されているフィールドの一般的な構文にのみ適用されます。
HTTP/2 は接続固有ヘッダーフィールドを示す Connection ヘッダーフィールド ([HTTP] の7.6.1節) を使用しません。このプロトコルでは、接続固有のメタデータは他の方法で転送されます。エンドポイントは接続固有ヘッダーフィールドを含む HTTP/2 メッセージを生成してはいけません (MUST NOT)。これには、Connection ヘッダーフィールドと、[HTTP] の7.6.1節で接続固有のセマンティクスを持つものとしてリストされているもの (すなわち、Proxy-Connection、Keep-Alive、Transfer-Encoding そして Upgrade) が含まれます。接続固有ヘッダーフィールドを含む全てのメッセージは不正な形式 (8.1.1節) として扱われなければなりません (MUST)。
これに関する唯一の例外は、TE ヘッダーフィールドです。このフィールドは HTTP/2 リクエストに存在してもよい (MAY) ものとしていますが、"trailers" 以外の値を含んではいけません (MUST NOT)。
HTTP/1.x メッセージを HTTP/2 に変換する中継者は、[HTTP] の7.6.1節に記載の接続固有ヘッダーフィールドを削除しなければなりません (MUST)。そうしなければ、それらのメッセージは他のエンドポイントから不正な形式 (8.1.1節) として扱われます。
注: HTTP/2 は他のプロトコルへのアップグレードに意図的に対応しません。3章で説明したハンドシェイク方式は、他のプロトコルの使用をネゴシエートするのに十分と考えられています。
Cookie ヘッダーフィールド [COOKIE] はクッキーペア (または "パンくず") の区切りにセミコロン (";") を使用します。このヘッダーフィールドは複数の値を含みますが、カンマ (",") を区切りに使用しないため、クッキーペアが複数のフィールド行 ([HTTP] の5.2節を参照) で送信されるのを妨げます。これは個々のクッキーペアに対する更新が HPACK テーブルに保存されている全てののフィールド行を無効化するため、圧縮効率が大幅に低下する可能性があります。
圧縮効率を向上させるために、Cookie ヘッダーフィールドは1つ以上のクッキーペアを持つ複数のヘッダーフィールドに分割してもよいものとします (MAY)。ヘッダー圧縮を解凍した後に、複数の Cookie ヘッダーフィールドが存在する場合、HTTP/1.1 コネクションや一般的なサーバーアプリケーションなどの非 HTTP/2 コンテキストに渡す前に、0x3b、0x20 (ASCII 文字の "; ") を2つのオクテットの区切り文字として使用し、それらは1つの文字列に結合されなければなりません (MUST)。
したがって、以下の Cookie ヘッダーフィールドの2つのリストは意味的に等しくなります。
cookie: a=b; c=d; e=f cookie: a=b cookie: c=d cookie: e=f
HTTP/2 では、メッセージ制御データ ([HTTP] の6.2節を参照) の転送に ':' 文字 (ASCII 0x3a) で始まる特殊な擬似ヘッダーフィールドを使用します。
擬似ヘッダーフィールドは HTTP ヘッダーフィールドではありません。エンドポイントはこの文書で定義されたもの以外の擬似ヘッダーフィールドを生成してはいけません (MUST NOT)。拡張は追加の疑似ヘッダーフィールドの使用をネゴシエートできることに注意してください (5.5節を参照)
擬似ヘッダーフィールドは、それらが定義されたコンテキストにおいてのみ有効です。リクエストのために定義された擬似ヘッダーフィールドは、レスポンスに使用してはいけません (MUST NOT)。同様に、レスポンスのために定義された擬似ヘッダーフィールドは、リクエストに使用してはいけません (MUST NOT)。擬似ヘッダーフィールドはトレイラーセクションに使用してはいけません (MUST NOT)。エンドポイントは、未定義や無効な擬似ヘッダーフィールドを含むリクエストやレスポンスを不正な形式 (8.1.1節) として扱わなければなりません (MUST)。
全ての擬似ヘッダーフィールドは、フィールドブロックにおいて全ての通常のフィールド行よりも前に出現しなければなりません (MUST)。フィールドブロックにおいて通常のフィールド行よりも後に擬似ヘッダーフィールドを含むリクエストやレスポンスは、不正な形式 (8.1.1節) として扱わなければなりません (MUST)。
同じ疑似ヘッダーフィールド名がフィールドブロックに2回以上出現してはいけません (MUST NOT)。疑似ヘッダーフィールド名を繰り返し含む HTTP リクエストやレスポンスのフィールドブロックは不正な形式 (8.1.1節) として扱わなければなりません (MUST)。
HTTP/2 リクエストでは、以下の擬似ヘッダーフィールドが定義されます:
":scheme" 擬似ヘッダーフィールドは、リクエスト対象のスキーム部を含みます。スキームは、リクエストを直接生成する場合は対象 URI ([RFC3986]、3.1節) から取得し、変換されたリクエスト (例えば、[HTTP/1.1] の3.3節を参照) ではそのスキームから取得します。CONNECT リクエスト (8.5節) ではスキームは省略されます。
":scheme" は "http" と "https" スキームの URI に制限されません。プロキシやゲートウェイは、非 HTTP スキームのリクエストを変換でき、非 HTTP サービスと通信をするために HTTP の使用を可能にします。
":authority" 擬似ヘッダーフィールドは、対象 URI ([HTTP] の7.1節) のオーソリティ部 ([RFC3986]、3.2節) を転送します。HTTP/2 リクエストの受信者は、":authority" が存在する場合は対象 URI を特定するために Host ヘッダーフィールドを使用してはいけません (MUST NOT)。
HTTP/2 リクエストを直接生成するクライアントは、転送するオーソリティの情報がない場合 (その場合は ":authority" を生成してはいけません (MUST NOT)) を除き、オーソリティの情報を転送するために ":authority" 疑似ヘッダーフィールドを使用しなければなりません (MUST)。
クライアントは ":authority" 疑似ヘッダーフィールドと異なる Host ヘッダーフィールドを持つリクエストを生成してはいけません (MUST NOT)。サーバーは ":authority" 疑似ヘッダーフィールドのエンティティとは異なるエンティティを示す Host ヘッダーフィールドを含むリクエストを不正な形式として扱うべきです (SHOULD)。これらのフィールドの値は比較のために正規化する ([RFC3986] の6.2節を参照) 必要があります。オリジンサーバーは任意の正規化処理を適用できますが、他のサーバーは2つのフィールドのスキームに基づく正規化 ([RFC3986] の6.2.3節を参照) を実行しなければなりません (MUST)。
HTTP/2 でリクエストを転送する中継者は、元のリクエストの対象 URI がオーソリティ情報を含まない場合 (その場合は ":authority" を生成してはならない) を除き、元のリクエストの制御データのオーソリティ情報を使用して ":authority" 疑似ヘッダーフィールドを構築しなければなりません (MUST)。Host ヘッダーフィールドはこの情報の唯一の情報源ではないことに注意してください ([HTTP] の7.2節)。
Host ヘッダーフィールドを生成する必要がある (HTTP/1.1 リクエストを構築するのに必要かもしれません) 中継者は、その中継者がリクエスト対象も変更しない限り、":authority" 疑似ヘッダーフィールドの値を Host フィールドの値として使用しなければなりません (MUST)。これは、HTTP ルーティングにおける潜在的な脆弱性を回避するために既存の Host フィールドを置き換えるものです。
HTTP/2 でリクエストを転送する中継者は、任意の Host ヘッダーフィールドを維持してもよいものとします (MAY)。
CONNECT やアスタリスク形式の OPTIONS リクエストのリクエスト対象は、オーソリティ情報を含まないことに注意してください ([HTTP] の7.1節と7.2節)。
":authority" は、"http" や "https" スキーム URI の非推奨となった "userinfo" サブコンポーネントを含めてはいけません (MUST NOT)。
":path" 擬似ヘッダーフィールドは、対象 URI のパス部とクエリー部 (絶対パスと文字 '?' の後に続く任意のクエリー、[HTTP] の4.1節を参照) を含みます。アスタリスク形式のリクエスト (OPTIONS 用) では、値 '*' を ":path" 擬似ヘッダーフィールドに含みます。
"http" や "https" の URI では、この擬似ヘッダーフィールドは空であってはいけません (MUST NOT)。パスコンポーネントを含まない "http" や "https" の URI では、値に '/' を含めなければなりません (MUST)。このルールの例外は次の通りです。
CONNECT リクエスト (8.5節) を除く全ての HTTP/2 リクエストは、":method"、":scheme"、そして ":path" 擬似ヘッダーフィールドに有効な値を必ず1つ含まなければなりません (MUST)。これらの擬似ヘッダーフィールドが省略された HTTP リクエストは不正な形式 (8.1.1節) になります。
個々の HTTP/2 リクエストはプロトコルバージョンの情報を転送しません。全ての HTTP/2 リクエストは暗黙的にプロトコルバージョン "2.0" を持ちます ([HTTP] の6.2節を参照)。
HTTP/2 レスポンスでは、HTTP ステータスコードフィールド ([HTTP] の15章を参照) を転送する ":status" 擬似ヘッダーフィールドを定義します。この擬似ヘッダーフィールドは中間レスポンスを含む全てのレスポンスに含まれなければなりません (MUST)。そうでない場合はそのレスポンスは不正な形式 (8.1.1節) になります。
HTTP/2 レスポンスは暗黙的にプロトコルバージョン "2.0" を持ちます。
HTTP/2 では、クライアントが事前に開始したリクエストに関連するレスポンスを (対応する "予約" リクエストと共に) サーバーがクライアントに先行送信 (または "プッシュ") することを可能にします。
サーバープッシュは、サーバーが受信したリクエストに続くリクエストを予測し、そのラウンドトリップを排除することでクライアント観点でのパフォーマンス向上を可能にするために設計されました。例えば、HTML へのリクエストの後にそのページが参照するスタイルシートやスクリプトのリクエストが続くことがよくあります。これらのリクエストがプッシュされると、クライアントは HTML でそれらへの参照を受信するのを待ち、個々のリクエストを発行する必要はありません。
実際には、キャッシュやコンテンツネゴシエーション、ユーザーの振る舞いなどの要素を考慮し、サーバーがクライアントが送信する追加のリクエストを正しく予測する必要があるため、サーバープッシュを効果的に使用することは困難です。予測の誤りは、追加データを転送する機会費用により、パフォーマンスの低下を引き起こす可能性があります。特に、大量のデータをプッシュするとより重要なレスポンスとの間で競合が発生する可能性があります。
クライアントはサーバープッシュの無効化を要求できますが、これはホップごとに独立してネゴシエートされます。SETTINGS_ENABLE_PUSH 設定を 0 に設定すると、サーバープッシュが無効であることを示します。
予約リクエストは安全 ([HTTP]、9.2.3節) でなければならず (MUST)、またキャッシュ可能 ([HTTP]、9.2.1節) でなければなりません (MUST)。予約リクエストにはコンテンツやトレイラーセクションを含めることはできません。キャッシュ可能でない、安全であると知られていない、またはコンテンツの存在を示す予約リクエストを受信したクライアントは、PROTOCOL_ERROR のストリームエラー (5.4.2節) と共に予約ストリームを初期化しなければなりません (MUST)。クライアントが新しく定義されたメソッドを安全であると認識できない場合、予約ストリームは初期化される可能性があることに注意してください。
キャッシュ可能 ([CACHING] の3章を参照) なプッシュレスポンスは、クライアントが HTTP キャッシュを実装している場合に保存されます。予約済みストリームIDにより識別されるストリームが open 状態の間、プッシュレスポンスはオリジンサーバーにおいて正常に検証された (例えば "no-cache" キャッシュレスポンスディレクティブ ([CACHING]、5.2.2.4節) が存在する場合) とみなされます。
キャッシュ可能でないプッシュレスポンスは HTTP キャッシュにより保存されてはいけません (MUST NOT)。それらはアプリケーションで別途利用できるようにしてもよいものとします (MAY)。
サーバーは、":authority" 擬似ヘッダーフィールドに、サーバーが権限を持つ値 (10.1節) を含めなければなりません (MUST)。クライアントはサーバーが権限を持たない PUSH_PROMISE を、PROTOCOL_ERROR のストリームエラー (5.4.2節) として扱わなければなりません (MUST)。
中間機器はサーバーからのプッシュを受信でき、クライアントへそれらを転送するかを選択できます。言い換えれば、プッシュされる情報をどのように使用するかは中間機器次第です。同様に、中間機器はサーバーによる動作なしに、クライアントへの追加のプッシュを生成する可能性があります。
クライアントはプッシュすることはできません。したがって、サーバーは PUSH_PROMISE フレームの受信を PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません。サーバーは SETTINGS_ENABLE_PUSH 設定に 0 以外の値を設定できません (6.5.2節を参照)。
サーバープッシュは、意味的にはサーバーがリクエストに対して応答することと同等ですが、そのリクエストも PUSH_PROMISE フレームとしてサーバーから送信されます。
PUSH_PROMISE フレームは、制御データとサーバーがリクエストに関連付けるリクエストヘッダーフィールドの完全なセットからなるフィールドブロックを含みます。メッセージコンテンツを含むリクエストのレスポンスをプッシュすることはできません。
プッシュリクエストは、常にクライアントからのリクエストに明確に関連付けられます。サーバーから送信される PUSH_PROMISE フレームは、明示的なリクエストのストリーム上に送信されます。PUSH_PROMSE フレームは予約済みストリームIDも含みます。それはサーバーで使用可能なストリームIDから選択されています (5.1.1節)。
PUSH_PROMISE のヘッダーフィールドと、その後に続く CONTINUATION フレームは、正しく完全なリクエストヘッダーフィールドのセット(8.3.1節) でなければなりません (MUST)。サーバーは、":method" ヘッダーフィールドに安全でキャッシュ可能なメソッドを含めなければなりません (MUST)。クライアントが、正しく完全なヘッダーフィールドのセットを含んでいない、または ":method" ヘッダーフィールドのメソッドが安全でない PUSH_PROMISE を受信した場合は、予約されたストリーム上で PROTOCOL_ERROR のストリームエラー (5.4.2節) として応答しなければなりません (MUST)。
サーバーは、予約済みレスポンスに関連するどんなフレームを送信するよりも前に、PUSH_PROMISE フレーム (6.6節) を送信すべきです (SHOULD)。これは、クライアントが PUSH_PROMISE フレームを受信する前に、リクエストを発行するといった競合を防ぎます。
例えば、サーバーが複数の画像ファイルへのリンクが埋め込まれた文書のリクエストを受信し、サーバーがそれらの画像をクライアントにプッシュすることを選択したとします。このような場合、その画像リンクを含む DATA フレームよりも前に PUSH_PROMISE を送信することで、クライアントがそれらの埋め込みリンクを見つける前にリソースがプッシュされるのを確認できることを保証します。同様に、フィールドブロックが参照するリソース (例えば、Link ヘッダーフィールドなど) をサーバーがプッシュする場合は、ヘッダーを送信する前に PUSH_PROMISE を送信することで、クライアントがそれらのリソースにリクエストしないことを保証します。
PUSH_PROMISE フレームはクライアントから送信してはいけません (MUST NOT)。
PUSH_PROMISE フレームは、クライアントが開始したストリームにおいてサーバーから送信されますが、そのストリームはサーバーに対して "open" または "half-closed (remote)" のいずれかの状態でなければなりません (MUST)。PUSH_PROMISE フレームは、レスポンスを構成するフレームの間に存在しますが、1つのフィールドブロックを構成する HEADERS と CONTINUATION フレームの間に入れ込むことはできません。
PUSH_PROMISE フレームの送信は、新しいストリームを生成し、そのストリームをサーバー上では "reserved (local)" 状態に、クライアント上では "reserved (remote)" 状態にします。
PUSH_PROMISE フレームを送信後、サーバーは予約されたストリームIDを使用するサーバーが開始したストリーム上でレスポンス (8.3.2節) と同じ様にプッシュレスポンスを送信し始めることができます。サーバーはこのストリームを使用して、8.1節で定義された一連のシーケンスを使用して HTTP レスポンスを送信します。このストリームは、最初の HEADERS フレームが送信された後、クライアントに対して "half-closed" 状態 (5.1節) になります。
クライアントが PUSH_PROMISE フレームを受信し、プッシュレスポンスを受け入れることを選択すると、クライアントは予約済みストリームが終了するまで、そのレスポンスに対してリクエストを発行すべきではありません (SHOULD NOT)。
クライアントが何らかの理由でサーバーからプッシュされたレスポンスの受信を望まないと判断した場合や、サーバーが予約済みレスポンスの送信開始まで時間がかかりすぎる場合には、クライアントは CANCEL または REFUSED_STREAM コードのいずれかを使用して RST_STREAM フレームと予約済みのストリームIDを送信できます。
クライアントは、サーバーが同時にプッシュできるレスポンスの数を制限するために、SETTINGS_MAX_CONCURRENT_STREAMS 設定を使用できます。値を0に設定したSETTINGS_MAX_CONCURRENT_STREAMS を通知することで、プッシュレスポンスの送信に必要となるストリームをサーバーが開くことを防止します。しかしながら、これは PUSH_PROMISE フレームを使用してサーバーがストリームを予約することは防止しません。予約済みストリームは同時ストリーム数の制限には含まれないためです。プッシュされたリソースの受信を望まないクライアントは、不要な予約済みストリームをリセットするか、SETTINGS_ENABLE_PUSH を0に設定する必要があります。
プッシュレスポンスを受信するクライアントは、サーバーが信頼できるか (10.1節)、またプッシュレスポンスを提供したプロキシが対応するリクエストを設定したかを検証しなければなりません (MUST)。例えば、DNS-ID ([RFC6125]を参照) が example.com の証明書を提供するサーバーが、>https://www.example.org/doc< のレスポンスをプッシュすることは認められていません。
PUSH_PROMISE レスポンスのストリームは HEADERS フレームで開始し、直ちにそのストリームをサーバー上では "half-closed (remote)" 状態に、クライアント上では "half-closed (local)" 状態にします。そして、END_STREAM フラグを設定したフレームにより終了し、ストリームは "closed" 状態になります。
注: クライアントはサーバープッシュに対して END_STREAM フラグを設定したフレームを送信してはいけません。
CONNECT メソッド ([HTTP]、9.3.6節) は HTTP 接続をリモートホストへのトンネルに変換するために使用されます。CONNECT は、"https" リソースをやりとりする目的でオリジンサーバーと TLS セッションを確立するために、主に HTTP プロキシで使用されます。
HTTP/2 における CONNECT メソッドは、接続全体をトンネルに変換するのではなく、リモートホストへの単一の HTTP/2 ストリーム上でトンネルを確立します。CONNECT ヘッダーセクションは8.3.1節 ("リクエスト擬似ヘッダーフィールド") で定義されているように構成されますが、一部に違いがあります。具体的には以下のようになります。
これらの制限に適合しない CONNECT リクエストは、不正な形式 (8.1.1) になります。
CONNECT に対応するプロキシは、":authority" 擬似ヘッダーフィールドに指定されたホストとポートに TCP 接続 [TCP] を確立します。コネクションの確立に成功すると、[HTTP]、9.3.6節で定義されるように、プロキシは 2xx ステータスコードを含む HEADERS フレームをクライアントに送信します。
両方のピアによる初期 HEADERS フレームの送信後、その後に続く全ての DATA フレームは TCP 接続上に送信されたデータに相当します。クライアントから送信された DATA フレームのフレームペイロードは、プロキシにより TCP サーバーに転送されます。TCP サーバーから受信したデータは、プロキシにより DATA フレームに変換されます。DATA 以外のフレームタイプやストリームの管理フレーム (RST_STREAM や WINDOW_UPDATE、PRIORITY) を接続ストリームには送信してはいけません (MUST NOT)。また、それらのフレームを受信した場合は、ストリームエラー (5.4.2節) として扱わなければなりません (MUST)。
TCP 接続はどちらのピアからも終了できます。DATA フレームの END_STREAM フラグは TCP_FIN ビットに相当するフラグとして扱われます。クライアントには END_STREAM フラグが設定されたフレームの受信後に、END_STREAM フラグが設定された DATA フレームの送信が期待されます。END_STREAM フラグが設定された DATA フレームを受信したプロキシは、最後の TCP セグメントに FIN ビットを設定したデータを送信します。FIN ビットが設定された TCP セグメントを受信したプロキシは、END_STREAM フラグが設定された DATA フレームを送信します。なお、最後の TCP セグメントや DATA フレームは空にすることが可能であることに注意してください。
TCP 接続エラーは RST_STREAM で通知されます。プロキシは、RST ビットが設定された TCP セグメントの受信を含む、TCP 接続におけるいかなるエラーも、CONNECT_ERROR のストリームエラー (5.4.2節) として扱います。同様に、ストリームや HTTP/2 接続のエラーを検出した場合、プロキシは RST ビットを設定した TCP セグメントを送信しなければなりません (MUST)。
HTTP/2 は 101 (Switching Protocols) 情報提供ステータスコード ([HTTP]、15.2.2節) に対応しません。
101 (Switching Protocols) のセマンティクスは、多重化されたプロトコルには適用されません。同様の機能は拡張された CONNECT [RFC8441] の使用により可能になる可能性があり、また他のプロトコルは HTTP/2 がその使用をネゴシエートするのに使うのと同じメカニズムを使用できます (3章を参照)。
一般的に、HTTP クライアントはエラーの性質 ([HTTP]、9.2.2節を参照) を決定する手段がないため、非冪等なリクエストを再試行できません。これはエラーの前に何らかのサーバーの処理が行われた可能性があり、その結果リクエストが再試行された場合に意図しない影響が生じる可能性があります。
HTTP/2 ではリクエストが処理されていないことをクライアントに保証するための2つのメカニズムを提供します。
処理されなかったリクエストは失敗ではありません。クライアントは冪等でないメソッドのリクエストであっても自動的に再試行してもよいものとします (MAY)。
サーバーはその事実を保証できない限り、ストリームが処理されていないことを示してはなりません (MUST NOT)。あるストリーム上のフレームがアプリケーション層に渡される場合、そのストリームに対して REFUSED_STREAM を使用してはならず、また GOAWAY フレームは与えられたストリームID以上のストリームIDを含まなければなりません (MUST)。
これらのメカニズムに加え、PING フレームはクライアントが簡単にコネクションをテストする方法を提供します。ミドルボックス (例えば NAT やロードバランサー) の中には、コネクションバインディングを黙って破棄するものがあるため、idle 状態にあるコネクションは壊れる可能性があります。PING フレームは、クライアントがリクエストを送信せずにコネクションが有効かどうかを安全にテストすることを可能にします。
この節では HTTP/1.1 のリクエストとレスポンスを示し、それと同等の HTTP/2 リクエストとレスポンスを説明します。
HTTP GET リクエストは制御データとリクエストヘッダーを含み、メッセージコンテンツは持たないため、HEADERS フレームとして送信されます。その後にはリクエストヘッダーフィールドのシリアライズされたブロックを含む0個以上の CONTINUATION フレームが続きます。以下の HEADERS フレームは END_HEADERS と END_STREAM の両方のフラグが設定され、CONTINUATION フレームは送信されません。
GET /resource HTTP/1.1 HEADERS Host: example.org ==> + END_STREAM Accept: image/jpeg + END_HEADERS :method = GET :scheme = https :authority = example.org :path = /resource host = example.org accept = image/jpeg
同様に、制御データとレスポンスヘッダーのみを含むレスポンスも、レスポンスヘッダーフィールドのシリアライズされたブロックを含む、HEADERS フレーム (とそれに続く0個以上の CONTINUATION フレーム) として転送されます。
HTTP/1.1 304 Not Modified HEADERS ETag: "xyzzy" ==> + END_STREAM Expires: Thu, 23 Jan ... + END_HEADERS :status = 304 etag = "xyzzy" expires = Thu, 23 Jan ...
制御データとリクエストヘッダーを含み、メッセージコンテンツを持つ HTTP POST リクエストは、リクエストヘッダーを含む HEADER フレームとその後に続く0個以上の CONTINUATION フレーム、さらにその後に続く1個以上の DATA フレームとして転送されます。最後の CONTINUATION (または HEADERS) フレームには、END_HEADERS フラグが設定され、最後の DATA フレームには END_STREAM フラグが設定されます。
POST /resource HTTP/1.1 HEADERS Host: example.org ==> - END_STREAM Content-Type: image/jpeg - END_HEADERS Content-Length: 123 :method = POST :authority = example.org :path = /resource {binary data} :scheme = https CONTINUATION + END_HEADERS content-type = image/jpeg host = example.org content-length = 123 DATA + END_STREAM {binary data}
任意のフィールド行を構成するデータは、フィールドブロックフラグメント間で分割される可能性があることに注意してください。この例におけるフィールド行のフレームへの割り当ては、あくまで例示のためのものになっています。
制御データとレスポンスヘッダーを含み、メッセージコンテンツを持つレスポンスは、HEADERS フレームとそれに続く、0個以上の CONTINUATION フレーム、さらにその後に続く1個以上の DATA フレームとして転送されます。最後の DATA フレームには END_STREAM フラグが設定されます。
HTTP/1.1 200 OK HEADERS Content-Type: image/jpeg ==> - END_STREAM Content-Length: 123 + END_HEADERS :status = 200 {binary data} content-type = image/jpeg content-length = 123 DATA + END_STREAM {binary data}
101 以外の 1xx ステータスコードを使用する情報提供レスポンスは HEADERS フレームとそれに続く0個以上の CONTINUATION フレームとして転送されます。
トレイラーセクションは、リクエストやレスポンスのフィールドブロックと全ての DATA フレームが送信された後に、フィールドブロックとして送信されます。トレイラーセクションを構成するフィールドブロックを開始する HEADERS フレームには、END_STREAM フラグが設定されます。
以下の例は、Expect ヘッダーフィールドに "100-continue" トークンを含むリクエストに対するレスポンスとして送信される 100 (Continue) ステータスコードとトレイラーセクションの両方を含みます。
HTTP/1.1 100 Continue HEADERS Extension-Field: bar ==> - END_STREAM + END_HEADERS :status = 100 extension-field = bar HTTP/1.1 200 OK HEADERS Content-Type: image/jpeg ==> - END_STREAM Transfer-Encoding: chunked + END_HEADERS Trailer: Foo :status = 200 content-type = image/jpeg 123 trailer = Foo {binary data} 0 DATA Foo: bar - END_STREAM {binary data} HEADERS + END_STREAM + END_HEADERS foo = bar
この章では、相互運用性を向上する HTTP プロトコルの属性や、既知のセキュリティ脆弱性に対象する方法、実装差異が起こる可能性を減らす方法などについて説明します。
HTTP/2 接続は持続的です。最高のパフォーマンスを得るために、(例えば、ユーザーが特定の Web ページから移動してしまった時など) サーバーとの通信がこれ以上は不要だと判断したり、サーバーがコネクションを終了するまでクライアントはコネクションを終了しないよう期待されます。
クライアントは、URI 由来のホストや、選択された代替サービス [ALT-SVC]、設定されたプロキシなどから与えられたホストとポートのペアに対して同時に2つ以上の HTTP/2 接続を開始すべきではありません (SHOULD NOT)。
クライアントは、利用可能なストリームID空間 (5.1.1節) が少なくなったコネクションの交換や TLS 接続用の鍵情報の更新、エラーが発生したコネクションの交換 (5.4.1節) のために、追加のコネクションを生成できます。
クライアントは、異なる Server Name Indication [TLS-EXT] の値が使われている同一のIPアドレスとTCPポートに対してや、異なる TLS クライアント証明書を提供するために、複数の接続を開始してもよいものとします (MAY)。しかし、同一の設定に対して複数の接続を生成することは避けるべきです (SHOULD)。
サーバーは、オープンしたコネクションを可能な限り長く維持することが推奨されますが、必要に応じてアイドル状態のコネクションを終了することが認められています。いずれかのエンドポイントがトランスポート層の TCP 接続の終了を選択した時、終了側のエンドポイントは最初に GOAWAY (6.8節) フレームを送信すべきです (SHOULD)。その結果、両方のエンドポイントは先に送信したフレームが処理されて緩やかに完了したのか、それとも残りの必要なタスクが中断されたのかを期待通りに確認できます。
オリジンサーバーに対するコネクションは、直接接続や CONNECT メソッド (8.5節) を使用して作成されたトンネルを通じての接続かに関わらず、複数の異なる authority コンポーネントの URI に対するリクエストの送信に再利用されてもよいものとします (MAY)。コネクションはオリジンサーバーに権限がある (10.1節) 限り、再利用できます。TLS のない TCP 接続では、これは同一のIPアドレスとして解決されるホストに依存します。
"https" リソースでのコネクションの再利用は、さらに URI のホストに対する有効な証明書を持つかどうかに依存します。サーバーから提供された証明書は、その URI のホストに対して新しい TLS 接続を確立する際に、クライアントが行ういかなる検証に対して満足するものでなければなりません (MUST)。1つの証明書で複数のオリジンに対する権限を確立できます。[HTTP] の4.3節では、サーバーが URI に対して権限があるかどうかをクライアントが判断する方法を説明しています。
一部のデプロイにおいては、複数のオリジンに対するコネクションの再利用が、誤ったオリジンサーバーへのリクエストの送信につながる可能性があります。例えば TLS の終端が、オリジンサーバーの選択に TLS Server Name Indication [TLS-EXT] を使用するミドルボックスによって行われている可能性があります。これは、サーバーがその他の点で権限があるにも関わらず、意図した対象でないサーバーに対して、クライアントがリクエストを送信してしまう可能性があることを意味します。
クライアントにおけるコネクションの再利用を望まないサーバーは、リクエストに対して 421 (Misdirected Request) をレスポンスとして返すことで、リクエストの権限がないことを示すことができます ([HTTP] の15.5.20節を参照)。
HTTP/2 のプロキシを使用するように設定されたクライアントは、単一のコネクションを通じてそのプロキシにリクエストを送信します。つまり、プロキシ経由で送信されたすべてのリクエストは、プロキシへの接続を再利用します。
HTTP/2 の実装は、TLS 上の HTTP/2 に対して TLS バージョン1.2 [TLS12] 以上を使用しなければなりません (MUST)。[TLSBCP] にある TLS の一般的な利用ガイダンスに即すべきであり (SHOULD)、加えて HTTP/2 特有の制限もあります。
TLS の実装は、TLS の Server Name Indication (SNI) [TLS-EXT] 拡張に対応しなければなりません (MUST)。サーバーがドメイン名 [DNS-TERMS] により識別される場合は、対象ホストを示す代替メカニズムが使用されない限り、クライアントは server_name TLS 拡張を送信しなければなりません (MUST)。
TLS 1.3 [TLS13]をネゴシエートする HTTP/2 デプロイメントのための要件は9.2.3節に含まれます。TLS 1.2 のデプロイメントは9.2.1節と9.2.2節の対象になります。実装にはこれに準拠する初期値の提供が推奨されますが、準拠についての最終的な責任はデプロイメントにあると認識されます。
この節では、HTTP/2 で使用可能な TLS 1.2 の機能セットの制限について述べます。デプロイメントの制限により、これらの制限が満たされない場合であっても、TLS ネゴシエーションを失敗できないかもしれません。エンドポイントは、これらの TLS 要件が満たされない HTTP/2 コネクションを、INADEQUATE_SECURITY のコネクションエラー (5.4.1節) と共に直ちに終了してもよいものとします (MAY)。
TLS 1.2 上の HTTP/2 のデプロイメントは圧縮を無効にしなければなりません (MUST)。TLS 圧縮は本来はそうなるべきではない情報の漏洩 [RFC3749] につながります。HTTP/2 は圧縮機能を提供しているため、一般的な圧縮は不要です。その圧縮機能は、よりコンテキストに配慮しており、それ故にパフォーマンスや安全性、その他の点から見ても利用が適切であると思われます。
TLS 1.2 上の HTTP/2 のデプロイメントは再ネゴシエーションを無効にしなければなりません (MUST)。エンドポイントは TLS 再ネゴシエーションを PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。再ネゴシエーションを無効にすると、使用する暗号スイートに暗号化できるメッセージ数の上限があるため、コネクションを長期に渡って使用できなくなる可能性があることに注意してください。
エンドポイントは、ハンドシェイクにおいて提示するクライアント証明書の機密保護のためには、再ネゴシエーションを使用してもよいものとします (MAY)。しかし、いかなる再ネゴシーエションも、コネクションプリフェイスの送信前におこなわなければなりません (MUST)。サーバーは、コネクションを確立した後すぐに再ネゴシエーション要求がされた場合は、クライアント証明書を要求すべきです (SHOULD)。
これは実質的に、特定の保護されたリソースに対するリクエストのレスポンスにおける再ネゴシエーションの使用を防止します。将来の仕様では、このユースケースのための手法が規定されるかもしれません。また、サーバーは、クライアントに再ネゴシエーションをサポートするプロトコルを使用させるために HTTP_1_1_REQUIRED のエラー (5.4節) を使用するかもしれません。
実装は、Ephemeral Finite Field Diffie-Hellman (DHE) ([TLS12] の8.1.2節) の暗号スイートに対しては最低でも2048ビット、Ephemeral Elliptic Curve Diffie-Hellman (ECDHE) [RFC8422] の暗号スイートに対しては最低でも224ビットの、エフェメラル鍵交換サイズに対応しなければなりません (MUST)。クライアントは DHE の大きさとして4096ビットまで受け入れなければなりません (MUST)。エンドポイントは、この制限よりも小さい鍵サイズのネゴシエーションを INADEQUATE_SECURITY のコネクションエラー (5.4.1節) として扱ってもよいものとします (MAY)。
TLS 1.2 上の HTTP/2 のデプロイメントは、付録Aに記載の禁止された暗号スイートを使用するべきではありません (SHOULD NOT)。
エンドポイントは、禁止された暗号スイートの1つでネゴシエートされた場合は、INADEQUATE_SECURITY のコネクションエラー (5.4.1節) を発生してもよいものとします (MAY)。禁止された暗号スイートの使用を選択するデプロイメントは、潜在的なピアのセットがその暗号スイートを受け入れることが知られていない限り、コネクションエラーを引き起こす危険があります。
実装は、禁止されていない暗号スイートのネゴシエーションに反応して、このエラーを生成してはいけません (MUST NOT)。クライアントが禁止されていない暗号スイートを提示してきた場合は、その暗号スイートを HTTP/2 で使用する準備をしなければなりません。
禁止された暗号スイートのリストは TLS 1.2 が実装を必須としている暗号スイートを含みます。これは、TLS 1.2 のデプロイメントが許可された暗号スイートの共通集合を見出せない可能性があることを意味します。TLS ハンドシェイクの失敗を引き起こすこの問題を避けるために、TLS 1.2 を使う HTTP/2 の実装は、楕円曲線 P-256 [RFC8422] を使用した TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 [TLS-ECDHE] に対応しなければなりません (MUST)。
クライアントは、HTTP/2 に対応しないサーバーへの接続を可能にするために、禁止された暗号スイートのサポートを通知する可能性があることに注意してください。これにより、サーバーは HTTP/2 で禁止された暗号スイートと共に HTTP/1.1 を選択できます。しかしながら、これはアプリケーションプロトコルと暗号スイートが独立して選択された場合に、禁止された暗号スイートと共に HTTP/2 がネゴシエートされる結果を生む可能性があります。
TLS 1.3 には以前のバージョンで利用できなかった多くの機能が含まれています。この節では、これらの機能の利用について説明します。
HTTP/2 サーバーはハンドシェイク後に TLS 1.3 CertificateRequest メッセージを送信してはなりません (MUST NOT)。HTTP/2 クライアントは、ハンドシェイク後の CertificateRequest メッセージを PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。
ハンドシェイク後の認証の禁止は、クライアントが "post_handshake_auth" TLS 拡張を提示した場合でも適用されます。ハンドシェイク後の認証のサポートは、ALPN [TLS-ALPN] とは独立して通知される可能性があります。クライアントは他のプロトコルで使用するための機能を提示する可能性がありますが、それらの拡張を含めることは HTTP/2 におけるサポートを意味するものではありません。
[TLS13] では他のハンドシェイク後のメッセージとして NewSessionTicket と KeyUpdate を定義しており、これらは HTTP/2 と直接の相互作用がないため利用できます。新しい種類の TLS メッセージの使用が、アプリケーション層のプロトコルとの相互作用に依存しない限り、その TLS メッセージはハンドシェイクの完了後に送信できます。
[RFC8470] のガイダンスを遵守すれば、TLS early data はリクエストの送信に使ってもよいものとします (MAY)。クライアントは全てのサーバー設定の初期値を仮定して、early data でリクエストを送信します。
TLS の使用は、このプロトコルのセキュリティ特性の多くを提供するために必要です。この章の要求の多くは、9.2節で説明したように TLS を使用しないと有効になりません。
HTTP/2 は、サーバーが対象のリソースの提供する権限があるかどうかを判定するために HTTP の権限の定義に依存しています ([HTTP]、4.3節)。"http" URI スキームではローカル名前解決、"https" スキームでは認証されたサーバー識別子にそれぞれ依存します。
クロスプロトコル攻撃では、攻撃者は異なるプロトコルを解釈するサーバーに対して、クライアントに最初のプロトコルでトランザクションを開始させます。これにより、攻撃者は第二のプロトコルの有効なトランザクションのように見えるトランザクションを開始できるかもしれません。Web コンテキストの機能と組み合わせることで、これはプライベートネットワーク内の不十分な保護下にあるサーバーと通信をするために使用できます。
HTTP/2 の ALPN 識別子と共に TLS ハンドシェイクを完了することは、クロスプロトコル攻撃に対して十分な保護になると考えられます。ALPN は他の TLS ベースのプロトコルへの攻撃を防ぎ、サーバーが HTTP/2 を処理するための前向きな意思表示を提供します。
TLS の暗号化は、攻撃者が平文プロトコル上でクロスプロトコル攻撃に使用するようなデータの制御を難しくします。
平文バージョンの HTTP/2 はクロスプロトコル攻撃に対する最低限の保護しか持ちません。コネクションプリフェイス (3.4節) は HTTP/1.1 サーバーを混乱させるように設計された文字列を含みますが、他のプロトコルに対する特別な保護を提供しません。
HPACK は他の HTTP のバージョンで区切り文字として扱われる可能性あのあるフィールド名と値のエンコーディングを許容します。HTTP/2 リクエストやレスポンスを変換する中継者は、他の HTTP バージョンにメッセージを変換する前に、8.2節のルールに従ってフィールドを検証しなければなりません (MUST)。不正な区切り文字を含むフィールドの変換は、受信者においてメッセージの不正な解釈を引き起こすために使われる可能性があり、攻撃者によって悪用される可能性があります。
8.2節には擬似ヘッダーフィールドの検証に関する特定のルールは含まれていません。これらのフィールドの値が使用される場合は追加の検証が必要です。これは ":scheme"、":authority"、":path" を組み合わせて、1つの URI 文字列 [RFC3986] を構成する場合に特に重要です。その URI や ":path" を ":method" と組み合わせてリクエスト行を構築する ([HTTP/1.1] の3章) 場合にも同様の問題が発生する可能性があります。入力値が完全に検証されない限り、単純な結合は安全ではありません。
の5章にある HTTP ABNF 文法に準拠していないフィールドといったように、他の理由で不正なフィールド名や値を含むフィールドを拒否できます。8.2節で要求される最小限のフィールドの検証以外を行わない中継者は、無効なフィールド名や値を含むメッセージを転送できます。 の7.6.1節を参照) を受信した中継者は、メッセージを転送する前にそれらのヘッダーフィールドを削除するか置換しなければならない (MUST)。さらに、中継者は Content-Length フィールドを含むメッセージを転送する際に、メッセージが適切な形式 (8.1.1節) であることを保証するために注意しなければならない。これは、どこかでメッセージが HTTP/1.1 に変換される場合にフレーミングが正しくなることを保証します。プッシュレスポンスとはクライアントからの明確なリクエストがないレスポンスです。リクエストは PUSH_PROMISE フレームによりサーバーから提供されます。
プッシュされたレスポンスのキャッシュは可能です。これはオリジンサーバーの Cache-Control ヘッダーフィールドが提供する指示に基づいておこなわれます。しかしながら、1つのサーバーホストが複数のテナントを提供する場合は、問題を引き起こす可能性があります。例えば、サーバーは複数のユーザーにそれぞれ URI 空間の一部を提供するかもしれません。
複数のテナントが同一サーバーの空間を共有する場合、サーバーは、テナントがリソースの権限を超えてキャッシュをプッシュしないことを保証しなければなりません (MUST)。これを強制しなければ、権限のあるテナントが提供する実際のキャッシュを上書きし、本来のキャッシュの外で提供されたキャッシュを、サーバーが提供することが可能になってしまいます。
権限のないオリジンサーバー (10.1節) のプッシュレスポンスを、キャッシュしたり使用してはいけません (MUST NOT)。
HTTP/2 接続は、HTTP/1.1 接続よりも機能のためにより大きなリソースの割り当てを要求します。フィールドセクション圧縮およびフロー制御の使用はより多くの状態の保持に依存します。これらの機能の設定は、各機能に対するメモリーの割り当てを厳密に制限することを保証します。
PUSH_PROMISE フレームの数は、同様の方法では制限できません。サーバープッシュを受け入れるクライアントは、"reserved (remote)" 状態にできるストリームの数を制限すべきです (SHOULD)。極端な数のサーバープッシュストリームは、ENHANCE_YOUR_CALM のストリームエラー (5.4.2節) として扱うことができます。
多くの HTTP/2 実装では、サービス拒否に対して脆弱であることが分かっています [NFLX-2019-002]。以下は、実装がサービス拒否攻撃の対象になる可能性がある既知の手法のリストです。
攻撃者が大量のフレームを送信待ちにできると、未処理の送信フレームの非効率な追跡が過負荷を生む可能性があります。ピアは大量のフレームを生成するために、いくつかのテクニックを利用できます。
SETTINGS の変更、小さなフレーム、フィールドセクション圧縮などの、サービス拒否に悪用される可能性のある機能のほとんどは正当な用途があります。これらの機能が負荷になるのは、それらが不必要にあるいは過剰に使われた時だけです。
これらの機能の使用状況を監視しないエンドポイントは、自身をサービス拒否のリスクに晒します。実装者はこれらの機能の使用を追跡し、その使用に制限を設けるべきです (SHOULD)。エンドポイントは、不審な挙動を ENHANCE_YOUR_CALM のコネクションエラー (5.4.1節) として扱ってもよいものとします (MAY)。
巨大なフィールドブロック (4.3節) は、実装に大量の状態をコミットさせる可能性があります。ルーティングにおいて重要なフィールド行は、最終的な宛先へのフィールドのストリーミングを妨げるようにフィールドブロックの終わりに出現する可能性があります。このような順序やキャッシュの正しさを保証するといった他の理由により、エンドポイントはフィールドブロック全体をバッファする必要があるかもしれないことを意味します。フィールドブロックのサイズに強い制限はないため、一部のエンドポイントではフィールドブロックに利用可能なメモリーに対して非常に多くのコミットを余儀なくされる可能性があります。
エンドポイントは、SETTINGS_MAX_HEADER_LIST_SIZE を使用して非圧縮フィールドブロックのサイズに適用される可能性がある制限をピアに通知できます。この設定は推奨であるため、エンドポイントはそのリクエストやレスポンスが不正な形式として扱われるリスクを負って、制限を超えるフィールドブロックを送信してもよいものとします (MAY)。この設定は接続固有であり、リクエストやレスポンスはより低い制限や不明な制限のあるホップに遭遇する可能性があります。中継者は、異なるピアから提示された値を通知することでこの問題の回避を試みることができますが、そのようにする義務はありません。
許容できない巨大なフィールドブロックを受信したサーバーは HTTP 431 (Request Header Fields Too Large) ステータスコード [RFC6585] を送信できます。クライアントは処理できないレスポンスを破棄できます。そのコネクションが終了されない限り、フィールドブロックは一貫性のあるコネクションの状態を維持するために処理されなければなりません (MUST)。
TCP 接続の生成や維持と比較すると、ストリームの生成は少ないコストで行えるため、CONNECT メソッドは、プロキシに過剰な負荷を生むために使用される可能性があります。プロキシは送信用の TCP 接続が TIME_WAIT 状態のままであれば、CONNECT リクエストを転送するストリームの終了後も、TCP 接続のための一部のリソースを維持する可能性があります。したがって、プロキシは CONNECT リクエストにより消費されるリソースを制限するために、SETTINGS_MAX_CONCURRENT_STREAMS だけに依存するということはできません。
圧縮は、攻撃者の制御下でかつ同じコンテキストで圧縮された場合に、攻撃者による機密データの復元を可能にします。HTTP/2 はフィールド行の圧縮 (4.3節) を可能にしますが、以下の懸念は HTTP の compressed content-coding ([HTTP]、8.4.1節) の使用にも適用されます。
Web の特性を利用した圧縮に関する攻撃手法 (例: [BREACH]) もあります。攻撃者は様々な平文を含む複数のリクエストを誘発し、得られた各暗号テキストの長さを観測します。推測した機密が正しければ、その長さは短くなります。
保護されたチャンネル上で通信する実装は、各データソースに異なる圧縮辞書を使わない限り、機密と攻撃者が制御するデータの両方を含む内容を圧縮してはいけません (MUST NOT)。データソースが確実に判断できない場合は、圧縮を使用してはいけません (MUST NOT)。TLS で提供されているような汎用的なストリーム圧縮は HTTP/2 で使用してはいけません (MUST NOT) (9.2節)。
HTTP/2 におけるパディングは、TLS [TLS13] で提供される一般的なパディングの置き換えを意図していません。冗長なパディングは逆効果にもなり得ます。正しいアプリケーションであるかどうかは、パディングされたデータに関する特別な情報を持つことによって決まります。
圧縮を利用した攻撃を軽減するための圧縮機能の無効化や制限は、対抗策としてのパディングよりも適しているかもしれません。
パッディングはフレームの内容の正確なサイズをわかりにくくするために使用でき、HTTP の特定の攻撃を軽減するために提供されます。例えば、攻撃者により制御されたプレーンテキストと機密データを含む圧縮コンテンツにおける攻撃 (例: [BREACH]) があります。
パディングの使用は、一見してわかる防御よりも結果的に弱い防御に終わることがあります。パディングは攻撃者が観察しなければならないフレームの数を増加させることで、長さ情報の推測をより困難にすることしかできません。不適切に実装されたパディングの構造は、簡単に破られる可能性があります。特に予測可能な分布によるランダムなパッディングは、非常にわずかな保護しか提供できません。同様に、パディングフレームペイロードを固定サイズにすることは、フレームペイロードサイズをその固定サイズの境界を超えるように変更することで、情報を漏洩させます。これは攻撃者がプレーンテキストの制御が可能な場合に起こりえます。
中継者は DATA フレームのパディングを維持すべきです (SHOUD)。しかしながら、HEADERS や PUSH_PROMISE フレームのパディングは削除してもよいものとします (MAY)。中継者がフレームのパディングの量を変更する正当な理由は、パディングが提供する保護を改善することにあります。
HTTP/2 のいくつかの特徴は、時間をかけてサーバーやクライアントの関連する動作を観測する機会を提供します。これには、設定の値やフロー制御ウインドウの管理方法、優先度がストリームに割り当てられる方法、攻撃に対する反応のタイミング、設定により制御される機能の扱いなどを含みます。
観測可能な振る舞いの違いを生み出す限り、[PRIVACY] の3.2節で定義されているように、特定クライアントのフィンガープリントの取得に使用することができてしまいます。
HTTP/2 が単一の TCP 接続を使用することで、サイト上でのユーザーの行動を相関させることが可能になります。異なるオリジンに対するコネクションの再利用は、それらのオリジンを超えての追跡を可能にします。
PING や SETTINGS フレームへの応答が直ちに求められるのは、これらのフレームがエンドポイントからピアへのレイテンシの計測に使用されるためです。これは、特定のシナリオでプライバシーへの影響があるかもしれません。
リモートタイミング攻撃は、サーバーが機密情報を使用するリクエストを処理する際にかかる時間の変動を観測することで、サーバーから機密情報を抽出するものです。HTTP/2 はリクエストの作成と処理を同時に行えるため、攻撃者はリクエストの処理を開始するタイミングをより細かく制御できます。複数の HTTP/2 リクエストは1つの同じ IP パケットや TLS レコードに含めることができます。これにより HTTP/2 は、リクエストの転送における変動性を排除し、リクエストの順序とレスポンスの転送のみを時間の変動要因に絞ることでリモートタイミング攻撃をより効率的に行えます。
処理時間が機密情報の値に依存しないようにすることは、あらゆる形態のタイミング攻撃に対する最も良い防御策です。
この HTTP/2 の改訂では、[RFC7540] で定義された HTTP2-Settings ヘッダーフィールドと、h2c アップグレードトークンを廃止します。
[RFC7540] の11章では、PRI HTTP メソッドと共に、h2 と h2c ALPN 識別子を登録しています。また、RFC 7540 では、フレームタイプ、設定、エラーコードのレジストリも確立しています。これらの登録とレジストリは HTTP/2 にも適用されますが、この文書では再定義されません。
IANA は次のレジストリにおける RFC 7540 への参照を、この文書を参照するように更新しました: "TLS Application-Layer Protocol Negotiation (ALPN) Protocol IDs"、"HTTP/2 Frame Type"、"HTTP/2 Settings"、"HTTP/2 Error Code"、 そして "HTTP Method Registry" です。PRI メソッドの登録は3.4節を参照するように更新され、それ以外の節番号は変更ありません。
IANA は、RFC 7540 で Experimental Use として予約されていた "HTTP/2 Frame Type" と "HTTP/2 Settings" のレジストリの一部についてポリシーを変更しました。対象部分は、各レジストリの残りの部分と同じポリシーで運用されます。
この節では、[RFC7540] の11.5節で "Hypertext Transfer Protocol (HTTP) Field Name Registry" に登録された HTTP2-Settings ヘッダーフィールドを廃止します。この機能は削除されました (3.1節を参照)。登録は [HTTP] の18.4節で要求される詳細を含むよう、次のとおり更新されます。
この節では、[RFC7540] の11.8節で "Hypertext Transfer Protocol (HTTP) Upgrade Token Registry" に登録された h2c アップグレードトークンの廃止を記録します。この機能は削除されました (3.1節を参照)。登録は次のとおり更新されます。
HTTP/2 実装は、TLS 1.2 での以下の暗号スイートによるネゴシエーションを INADEQUATE_SECURITY のコネクションエラー (5.4.1節) として扱ってもよいものとします (MAY):
注: このリストは、執筆時に登録されている TLS 暗号スイートのセットから構成されています。このリストには、一時鍵の交換を提供しない暗号スイートや、TLS null、ストリームまたはブロック暗号 ([TLS12]、6.2.3節で定義) に分類される種類の暗号スイートを含んでいます。これらと同様の性質を持つ追加の暗号スイートは定義可能ですが、それらは明示的に禁止されません。
詳細は9.2.2節を参照してください。
この改訂では、次のような実質的な変更を行いました。
編集上の変更も含まれます。特に、用語や文書構造の変更はコア HTTP セマンティクス [HTTP] の更新に対応するものです。これらの文書は、ステータスコード 421 や connection coalescing など、RFC 7540 で最初に定義されたいくつかの概念を含みます。
この文書への重要な意見は、長年にわたって HTTP ワーキンググループに貢献してきた多くの人々による功績です。[RFC7540] には、彼らの貢献に対して謝辞を述べるに値する、より広範囲な人々のリストが含まれています。
この文書の基礎となる文章は、Mike Belshe と Roberto Peon によって執筆されました。