5. ストリームと多重化
「ストリーム」は、HTTP/2接続内でクライアントとサーバー間で交換される独立した双方向のフレームシーケンスです。ストリームにはいくつかの重要な特性があります:
-
単一のHTTP/2接続には、複数の同時にオープンされたストリームを含むことができ、いずれのエンドポイントも複数のストリームからのフレームをインターリーブできます。
-
ストリームは、一方的に確立および使用されるか、クライアントまたはサーバーのいずれかによって共有されます。
-
ストリームは、いずれかのエンドポイントによって閉じることができます。
-
ストリーム上でフレームが送信される順序は重要です。受信者は、受信した順序でフレームを処理します。特に、HEADERSフレームとDATAフレームの順序は意味的に重要です。
-
ストリームは整数で識別されます。ストリーム識別子は、ストリームを開始したエンドポイントによってストリームに割り当てられます。
5.1. ストリームの状態
ストリームのライフサイクルを図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 |
`----------------------->| |<----------------------'
+--------+
send: endpoint sends this frame
recv: endpoint receives this frame
H: HEADERS frame (with implied CONTINUATION frames)
PP: PUSH_PROMISE frame (with implied CONTINUATION frames)
ES: END_STREAM flag
R: RST_STREAM frame
図2:ストリームの状態
この図は、ストリームの状態遷移と、それらの状態変更に影響を与えるフレームとフラグのみを示していることに注意してください。この点で、CONTINUATIONフレームは状態遷移を引き起こさず、実質的にそれらが続くHEADERSまたはPUSH_PROMISEフレームの一部です。状態遷移の目的では、END_STREAMフラグは、それを保持するフレームとは別のイベントとして処理されます。END_STREAMフラグが設定されたHEADERSフレームは、2つの状態遷移を引き起こす可能性があります。
両方のエンドポイントは、フレームが転送中である場合に異なる可能性があるストリームの状態について主観的な見方を持っています。エンドポイントはストリームの作成を調整しません。それらは、いずれかのエンドポイントによって一方的に作成されます。状態の不一致の悪影響は、RST_STREAMを送信した後の「closed」状態に限定され、閉じた後しばらくの間フレームが受信される可能性があります。
ストリームには次の状態があります:
idle:すべてのストリームは「idle」状態から始まります。
この状態から有効な遷移は次のとおりです:
-
HEADERSフレームの送信または受信により、ストリームは「open」になります。ストリーム識別子は、セクション5.1.1で説明されているように選択されます。同じHEADERSフレームは、ストリームをすぐに「half-closed」にすることもできます。
-
別のストリーム上でPUSH_PROMISEフレームを送信すると、後で使用するために識別されたidleストリームが予約されます。予約されたストリームのストリーム状態は「reserved (local)」に遷移します。
-
別のストリーム上でPUSH_PROMISEフレームを受信すると、後で使用するために識別されたidleストリームが予約されます。予約されたストリームのストリーム状態は「reserved (remote)」に遷移します。
-
PUSH_PROMISEフレームはidleストリーム上では送信されず、Promised Stream IDフィールドで新しく予約されたストリームを参照することに注意してください。
この状態のストリームでHEADERSまたはPRIORITY以外のフレームを受信した場合、PROTOCOL_ERRORタイプの接続エラー(セクション5.4.1)として扱わなければなりません(MUST)。
reserved (local):「reserved (local)」状態のストリームは、PUSH_PROMISEフレームを送信することによって約束されたものです。PUSH_PROMISEフレームは、リモートピアによって開始されたオープンストリームとストリームを関連付けることによって、idleストリームを予約します(セクション8.4を参照)。
この状態では、次の遷移のみが可能です:
-
エンドポイントはHEADERSフレームを送信できます。これにより、ストリームが「half-closed (remote)」状態でオープンになります。
-
いずれかのエンドポイントは、ストリームを「closed」にするためにRST_STREAMフレームを送信できます。これにより、ストリームの予約が解放されます。
エンドポイントは、この状態でHEADERS、RST_STREAM、またはPRIORITY以外のタイプのフレームを送信してはなりません(MUST NOT)。
この状態では、PRIORITYまたはWINDOW_UPDATEフレームを受信する可能性があります(MAY)。この状態のストリームでRST_STREAM、PRIORITY、またはWINDOW_UPDATE以外のタイプのフレームを受信した場合、PROTOCOL_ERRORタイプの接続エラー(セクション5.4.1)として扱わなければなりません(MUST)。
reserved (remote):「reserved (remote)」状態のストリームは、リモートピアによって予約されたものです。
この状態では、次の遷移のみが可能です:
-
HEADERSフレームを受信すると、ストリームは「half-closed (local)」に遷移します。
-
いずれかのエンドポイントは、ストリームを「closed」にするためにRST_STREAMフレームを送信できます。これにより、ストリームの予約が解放されます。
エンドポイントは、この状態で予約されたストリームを再優先順位付けするためにPRIORITYフレームを送信できます(MAY)。エンドポイントは、この状態でRST_STREAM、WINDOW_UPDATE、またはPRIORITY以外のタイプのフレームを送信してはなりません(MUST NOT)。
この状態のストリームでHEADERS、RST_STREAM、またはPRIORITY以外のタイプのフレームを受信した場合、PROTOCOL_ERRORタイプの接続エラー(セクション5.4.1)として扱わなければなりません(MUST)。
open:「open」状態のストリームは、両方のピアが任意のタイプのフレームを送信するために使用できます。この状態では、送信ピアは通知されたストリームレベルのフロー制御制限(セクション5.2)を遵守します。
この状態から、いずれかのエンドポイントはEND_STREAMフラグが設定されたフレームを送信でき、これによりストリームは「half-closed」状態の1つに遷移します。END_STREAMフラグを送信するエンドポイントは、ストリーム状態を「half-closed (local)」にします。END_STREAMフラグを受信するエンドポイントは、ストリーム状態を「half-closed (remote)」にします。
いずれかのエンドポイントは、この状態からRST_STREAMフレームを送信でき、これによりすぐに「closed」に遷移します。
half-closed (local):「half-closed (local)」状態のストリームは、WINDOW_UPDATE、PRIORITY、およびRST_STREAM以外のフレームの送信には使用できません。
ストリームは、END_STREAMフラグが設定されたフレームを受信したとき、またはいずれかのピアがRST_STREAMフレームを送信したときに、この状態から「closed」に遷移します。
エンドポイントは、この状態で任意のタイプのフレームを受信できます。WINDOW_UPDATEフレームを使用してフロー制御クレジットを提供することは、フロー制御されたフレームを受信し続けるために必要です。この状態では、受信者は、END_STREAMフラグが設定されたフレームを送信した後、短期間到着する可能性があるWINDOW_UPDATEフレームを無視できます。
この状態で受信されたPRIORITYフレームは、識別されたストリームに依存するストリームを再優先順位付けするために使用されます。
half-closed (remote):「half-closed (remote)」であるストリームは、ピアによってフレームを送信するためにもはや使用されていません。この状態では、エンドポイントは受信者フロー制御ウィンドウを維持する義務がなくなります。
エンドポイントがこの状態のストリームに対してWINDOW_UPDATE、PRIORITY、またはRST_STREAM以外の追加のフレームを受信した場合、STREAM_CLOSEDタイプのストリームエラー(セクション5.4.2)で応答しなければなりません(MUST)。
「half-closed (remote)」であるストリームは、エンドポイントが任意のタイプのフレームを送信するために使用できます。この状態では、エンドポイントは通知されたストリームレベルのフロー制御制限(セクション5.2)を引き続き遵守します。
ストリームは、END_STREAMフラグが設定されたフレームを送信するか、いずれかのピアがRST_STREAMフレームを送信することによって、この状態から「closed」に遷移できます。
closed:「closed」状態は終端状態です。
エンドポイントは、閉じたストリーム上でPRIORITY以外のフレームを送信してはなりません(MUST NOT)。RST_STREAMを受信した後にPRIORITY以外のフレームを受信するエンドポイントは、それをSTREAM_CLOSEDタイプのストリームエラー(セクション5.4.2)として扱わなければなりません(MUST)。同様に、END_STREAMフラグが設定されたフレームを受信した後にフレームを受信するエンドポイントは、以下で説明されているようにフレームが許可されている場合を除き、それをSTREAM_CLOSEDタイプの接続エラー(セクション5.4.1)として扱わなければなりません(MUST)。
WINDOW_UPDATEまたはRST_STREAMフレームは、END_STREAMフラグを含むDATAまたはHEADERSフレームを送信した後、短期間この状態で受信される可能性があります。リモートピアがRST_STREAMまたはEND_STREAMフラグを含むフレームを受信して処理するまで、これらのタイプのフレームを送信する可能性があります。エンドポイントは、この状態で受信されたWINDOW_UPDATEまたはRST_STREAMフレームを無視しなければなりません(MUST)が、エンドポイントは、END_STREAMを送信した後かなりの時間が経過してから到着するフレームをPROTOCOL_ERRORタイプの接続エラー(セクション5.4.1)として扱うことを選択できます(MAY)。
PRIORITYフレームは、閉じたストリームに依存するストリームを優先順位付けするために、閉じたストリーム上で送信できます。エンドポイントは、PRIORITYフレームを処理すべきです(SHOULD)が、ストリームが依存関係ツリーから削除されている場合は無視できます([RFC7540]のセクション5.3.3を参照)。
この状態がRST_STREAMフレームを送信した結果として到達した場合、RST_STREAMを受信するピアは、取り消すことができないストリーム上のフレームをすでに送信した、または送信のためにキューに入れた可能性があります。エンドポイントは、RST_STREAMフレームを送信した後、閉じたストリーム上で受信するフレームを無視しなければなりません(MUST)。エンドポイントは、フレームを無視する期間を制限し、この時間の後に到着するフレームをエラーとして扱うことを選択できます(MAY)。
RST_STREAMを送信した後に受信されたフロー制御されたフレーム(つまりDATA)は、接続フロー制御ウィンドウにカウントされます。これらのフレームは無視される可能性がありますが、送信者がRST_STREAMを受信する前に送信されるため、送信者はフレームがフロー制御ウィンドウに対してカウントされると見なします。
エンドポイントは、RST_STREAMを送信した後にPUSH_PROMISEフレームを受信する可能性があります。PUSH_PROMISEは、関連するストリームがリセットされた場合でも、ストリームを「reserved」にします。したがって、不要な約束されたストリームを閉じるにはRST_STREAMが必要です。
より具体的なルールがない場合、実装は、状態の説明で明示的に許可されていないフレームの受信をPROTOCOL_ERRORタイプの接続エラー(セクション5.4.1)として扱うべきです(SHOULD)。PRIORITYは任意のストリーム状態で送信および受信できることに注意してください。
このセクションのルールは、このドキュメントで定義されたフレームにのみ適用されます。セマンティクスが不明なフレームの受信は、それらのフレームを送受信するための条件も不明であるため、エラーとして扱うことはできません。セクション5.5を参照してください。
HTTPリクエスト/レスポンス交換の状態遷移の例は、セクション8.8にあります。サーバープッシュの状態遷移の例は、セクション8.4.1および8.4.2にあります。
5.1.1. ストリーム識別子
ストリームは、符号なし31ビット整数で識別されます。クライアントによって開始されたストリームは、奇数番号のストリーム識別子を使用しなければなりません(MUST)。サーバーによって開始されたストリームは、偶数番号のストリーム識別子を使用しなければなりません(MUST)。ゼロ(0x00)のストリーム識別子は、接続制御メッセージに使用されます。ゼロのストリーム識別子は、新しいストリームを確立するために使用できません。
新しく確立されたストリームの識別子は、開始エンドポイントが開いたまたは予約したすべてのストリームよりも数値的に大きくなければなりません(MUST)。これは、HEADERSフレームを使用して開かれるストリームと、PUSH_PROMISEを使用して予約されるストリームを規定します。予期しないストリーム識別子を受信するエンドポイントは、PROTOCOL_ERRORタイプの接続エラー(セクション5.4.1)で応答しなければなりません(MUST)。
HEADERSフレームは、フレームヘッダーのストリーム識別子によって識別されるクライアント開始ストリームを「idle」から「open」に遷移させます。PUSH_PROMISEフレームは、フレームペイロードのPromised Stream IDフィールドによって識別されるサーバー開始ストリームを「idle」から「reserved (local)」または「reserved (remote)」に遷移させます。ストリームが「idle」状態から遷移すると、より低い値のストリーム識別子を持つピアによって開かれた可能性のある「idle」状態のすべてのストリームは、すぐに「closed」に遷移します。つまり、エンドポイントはストリーム識別子をスキップでき、その効果はスキップされたストリームがすぐに閉じられることです。
ストリーム識別子は再利用できません。長寿命の接続により、エンドポイントが利用可能なストリーム識別子の範囲を使い果たす可能性があります。新しいストリーム識別子を確立できないクライアントは、新しいストリームのために新しい接続を確立できます。新しいストリーム識別子を確立できないサーバーは、GOAWAYフレームを送信して、クライアントが新しいストリームのために新しい接続を開くことを強制できます。
5.1.2. ストリームの並行性
ピアは、SETTINGSフレーム内のSETTINGS_MAX_CONCURRENT_STREAMSパラメータ(セクション6.5.2を参照)を使用して、同時にアクティブなストリームの数を制限できます。最大同時ストリーム設定は、各エンドポイントに固有であり、設定を受信するピアにのみ適用されます。つまり、クライアントはサーバーが開始できる同時ストリームの最大数を指定し、サーバーはクライアントが開始できる同時ストリームの最大数を指定します。
「open」状態または「half-closed」状態のいずれかにあるストリームは、エンドポイントが開くことが許可されているストリームの最大数にカウントされます。これら3つの状態のいずれかにあるストリームは、SETTINGS_MAX_CONCURRENT_STREAMS設定で通知された制限にカウントされます。「reserved」状態のいずれかにあるストリームは、ストリーム制限にカウントされません。
エンドポイントは、ピアによって設定された制限を超えてはなりません(MUST NOT)。通知された同時ストリーム制限を超えるHEADERSフレームを受信するエンドポイントは、それをPROTOCOL_ERRORまたはREFUSED_STREAMタイプのストリームエラー(セクション5.4.2)として扱わなければなりません(MUST)。エラーコードの選択は、エンドポイントが自動再試行を有効にしたいかどうかを決定します(詳細についてはセクション8.7を参照)。
SETTINGS_MAX_CONCURRENT_STREAMSの値を現在の開いているストリームの数よりも低い値に減らしたいエンドポイントは、新しい値を超えるストリームを閉じるか、ストリームが完了するのを許可できます。
5.2. フロー制御
多重化にストリームを使用すると、TCP接続の使用をめぐる競合が発生し、ストリームがブロックされる結果になります。フロー制御スキームは、同じ接続上のストリームが互いに破壊的に干渉しないことを保証します。フロー制御は、個々のストリームと接続全体の両方に使用されます。
HTTP/2は、WINDOW_UPDATEフレーム(セクション6.9)の使用を通じてフロー制御を提供します。
5.2.1. フロー制御の原則
HTTP/2ストリームフロー制御は、プロトコル変更を必要とせずに、さまざまなフロー制御アルゴリズムを使用できるようにすることを目的としています。HTTP/2のフロー制御には、次の特性があります:
-
フロー制御は接続固有です。HTTP/2フロー制御は、単一のホップのエンドポイント間で動作し、エンドツーエンドパス全体では動作しません。
-
フロー制御はWINDOW_UPDATEフレームに基づいています。受信者は、ストリーム上および接続全体で受信する準備ができているオクテット数を通知します。これはクレジットベースのスキームです。
-
フロー制御は方向性があり、受信者によって全体的な制御が提供されます。受信者は、各ストリームおよび接続全体に対して希望する任意のウィンドウサイズを設定することを選択できます(MAY)。送信者は、受信者によって課されたフロー制御制限を尊重しなければなりません(MUST)。クライアント、サーバー、および仲介者はすべて、受信者としてフロー制御ウィンドウを独立して通知し、送信時にピアによって設定されたフロー制御制限を遵守します。
-
フロー制御ウィンドウの初期値は、新しいストリームおよび接続全体の両方で65,535オクテットです。
-
フレームタイプは、フロー制御がフレームに適用されるかどうかを決定します。このドキュメントで指定されているフレームの中で、DATAフレームのみがフロー制御の対象となります。他のすべてのフレームタイプは、通知されたフロー制御ウィンドウのスペースを消費しません。これにより、重要な制御フレームがフロー制御によってブロックされないことが保証されます。
-
エンドポイントは、独自のフロー制御を無効にすることを選択できますが、エンドポイントはピアからのフロー制御信号を無視できません。
-
HTTP/2は、WINDOW_UPDATEフレーム(セクション6.9)の形式とセマンティクスのみを定義します。このドキュメントは、受信者がこのフレームをいつ送信するか、または送信する値を規定していませんし、送信者がパケットを送信する方法を指定していません。実装は、ニーズに合った任意のアルゴリズムを選択できます。
実装は、リクエストとレスポンスの送信を優先順位付けし、リクエストのヘッドオブラインブロッキングを回避する方法を選択し、新しいストリームの作成を管理する責任もあります。これらのアルゴリズムの選択は、任意のフロー制御アルゴリズムと相互作用する可能性があります。
5.2.2. フロー制御の適切な使用
フロー制御は、リソース制約の下で動作しているエンドポイントを保護するために定義されています。たとえば、プロキシは多くの接続間でメモリを共有する必要があり、低速なアップストリーム接続と高速なダウンストリーム接続を持つ可能性があります。フロー制御は、受信者が1つのストリーム上のデータを処理できないが、同じ接続上の他のストリームを処理し続けたい場合に対処します。
この機能を必要としないデプロイメントは、最大サイズ(2^31-1)のフロー制御ウィンドウを通知し、データを受信したときにWINDOW_UPDATEフレームを送信することによってこのウィンドウを維持できます。これにより、その受信者のフロー制御が効果的に無効になります。逆に、送信者は常に受信者によって通知されたフロー制御ウィンドウの対象となります。
リソースが制約されているデプロイメント(たとえば、メモリ)は、ピアが消費できるメモリの量を制限するためにフロー制御を使用できます。ただし、帯域幅*遅延積([RFC7323]を参照)の知識なしにフロー制御が有効になっている場合、利用可能なネットワークリソースの最適でない使用につながる可能性があることに注意してください。
現在の帯域幅*遅延積を完全に認識している場合でも、フロー制御の実装は困難です。エンドポイントは、データが利用可能になり次第、TCP受信バッファからHTTP/2フレームを読み取って処理しなければなりません(MUST)。迅速に読み取らないと、WINDOW_UPDATEなどの重要なフレームが読み取られて対応されない場合にデッドロックにつながる可能性があります。フレームを迅速に読み取ることは、HTTP/2フロー制御がリソースコミットメントを制限するため、エンドポイントをリソース枯渇攻撃にさらすことはありません。
5.2.3. フロー制御のパフォーマンス
エンドポイントが、ピアがこの接続上のピアの帯域幅*遅延積よりも大きい利用可能なフロー制御ウィンドウスペースを常に持っていることを保証できない場合、その受信スループットはHTTP/2フロー制御によって制限されます。これにより、パフォーマンスが低下します。
タイムリーなWINDOW_UPDATEフレームの送信は、パフォーマンスを向上させることができます。エンドポイントは、受信スループットを向上させる必要性とリソース枯渇リスクを管理する必要性のバランスを取りたいと考え、ウィンドウサイズを管理する戦略を定義する際にセクション10.5に注意を払うべきです(SHOULD)。
5.3. 優先順位付け
HTTP/2のような多重化プロトコルでは、ストリームへの帯域幅と計算リソースの割り当てを優先順位付けすることが、良好なパフォーマンスを達成するために重要です。不十分な優先順位付けスキームは、HTTP/2が不十分なパフォーマンスを提供する結果になる可能性があります。TCPレイヤーでの並列性がない場合、パフォーマンスはHTTP/1.1よりも大幅に悪化する可能性があります。
優れた優先順位付けスキームは、リソースのコンテンツ、リソースがどのように相互に関連しているか、およびこれらのリソースがピアによってどのように使用されるかなどのコンテキスト知識の適用から恩恵を受けます。特に、クライアントは、サーバーの優先順位付けに関連するリクエストの優先順位に関する知識を持つことができます。これらの場合、クライアントが優先順位情報を提供することで、パフォーマンスを向上させることができます。
5.3.1. RFC 7540における優先順位の背景
RFC 7540は、リクエストの優先順位を通知するための豊富なシステムを定義しました。しかし、このシステムは複雑であることが判明し、均一に実装されませんでした。
柔軟なスキームは、クライアントが非常に異なる方法で優先順位を表現することが可能であり、採用されたアプローチにはほとんど一貫性がありませんでした。サーバーにとって、スキームの汎用サポートの実装は複雑でした。優先順位の実装は、クライアントとサーバーの両方で不均一でした。多くのサーバーデプロイメントは、リクエストの処理を優先順位付けする際にクライアントシグナルを無視しました。
要するに、RFC 7540 [RFC7540]の優先順位通知は成功しませんでした。
5.3.2. このドキュメントにおける優先順位通知
このHTTP/2の更新は、RFC 7540 [RFC7540]で定義された優先順位通知を非推奨にします。優先順位シグナルに関連するテキストの大部分は、このドキュメントには含まれていません。フレームフィールドの説明と一部の必須処理は保持され、このドキュメントの実装がRFC 7540で説明されている優先順位通知を使用する実装と相互運用可能であることを保証します。
RFC 7540優先順位スキームの徹底的な説明は、[RFC7540]のセクション5.3に残っています。
優先順位情報の通知は、多くの場合、良好なパフォーマンスを達成するために必要です。優先順位情報の通知が重要である場合、エンドポイントは、[HTTP-PRIORITY]で説明されているスキームなどの代替スキームを使用することが推奨されます。
RFC 7540からの優先順位通知は広く採用されていませんでしたが、より良い情報がない場合、それが提供する情報は依然として有用です。HEADERSまたはPRIORITYフレームで優先順位シグナルを受信するエンドポイントは、その情報を適用することから恩恵を受けることができます。特に、これらのシグナルを消費する実装は、代替手段がない場合にこれらの優先順位シグナルを破棄することから恩恵を受けません。
サーバーは、優先順位シグナルがない場合、リクエストの優先順位を決定する際に他のコンテキスト情報を使用すべきです(SHOULD)。サーバーは、シグナルの完全な欠如を、クライアントが機能を実装していない兆候として解釈してもかまいません(MAY)。[RFC7540]のセクション5.3.5で説明されているデフォルトは、ほとんどの条件下で不十分なパフォーマンスを持つことが知られており、その使用は意図的である可能性は低いです。
5.4. エラー処理
HTTP/2フレーミングは、2つのクラスのエラーを許可します:
-
接続全体を使用不可能にするエラー条件は、接続エラーです。
-
個々のストリームのエラーは、ストリームエラーです。
エラーコードのリストは、セクション7に含まれています。
エンドポイントが複数のエラーを引き起こすフレームに遭遇する可能性があります。実装は処理中に複数のエラーを発見する可能性がありますが(MAY)、結果として最大1つのストリームエラーと1つの接続エラーを報告すべきです(SHOULD)。
特定のストリームに対して報告された最初のストリームエラーは、そのストリームの他のエラーが報告されるのを防ぎます。対照的に、プロトコルは複数のGOAWAYフレームを許可しますが、エンドポイントは、グレースフルシャットダウン中にエラーが発生しない限り、1つのタイプの接続エラーのみを報告すべきです(SHOULD)。これが発生した場合、エンドポイントは、NO_ERRORを含む以前のGOAWAYに加えて、新しいエラーコードを含む追加のGOAWAYフレームを送信してもかまいません(MAY)。
エンドポイントが複数の異なるエラーを検出した場合、それらのエラーのいずれかを報告することを選択してもかまいません(MAY)。フレームが接続エラーを引き起こす場合、そのエラーを報告しなければなりません(MUST)。さらに、エンドポイントは、エラー条件を検出したときに適用可能な任意のエラーコードを使用してもかまいます(MAY)。汎用エラーコード(PROTOCOL_ERRORやINTERNAL_ERRORなど)は、常により具体的なエラーコードの代わりに使用できます。
5.4.1. 接続エラー処理
接続エラーは、フレームレイヤーのさらなる処理を妨げるか、接続状態を破壊するエラーです。
接続エラーに遭遇したエンドポイントは、まず、ピアから正常に受信した最後のストリームのストリーム識別子を含むGOAWAYフレーム(セクション6.8)を送信すべきです(SHOULD)。GOAWAYフレームには、接続が終了している理由を示すエラーコード(セクション7)が含まれています。エラー条件に対してGOAWAYフレームを送信した後、エンドポイントはTCP接続を閉じなければなりません(MUST)。
GOAWAYが受信エンドポイントによって確実に受信されない可能性があります。接続エラーの場合、GOAWAYは、接続が終了している理由についてピアと通信するためのベストエフォートの試みのみを提供します。
エンドポイントは、いつでも接続を終了できます。特に、エンドポイントはストリームエラーを接続エラーとして扱うことを選択してもかまいません(MAY)。エンドポイントは、状況が許す場合、接続を終了するときにGOAWAYフレームを送信すべきです(SHOULD)。
5.4.2. ストリームエラー処理
ストリームエラーは、他のストリームの処理に影響を与えない特定のストリームに関連するエラーです。
ストリームエラーを検出したエンドポイントは、エラーが発生したストリームのストリーム識別子を含む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)。
5.4.3. 接続終了
ストリームが「open」または「half-closed」状態のままでTCP接続が閉じられたりリセットされたりした場合、影響を受けるストリームは自動的に再試行できません(詳細についてはセクション8.7を参照)。
5.5. HTTP/2の拡張
HTTP/2はプロトコルの拡張を許可します。このセクションで説明されている制限内で、プロトコル拡張を使用して追加のサービスを提供したり、プロトコルの任意の側面を変更したりできます。拡張は、単一のHTTP/2接続のスコープ内でのみ有効です。
これは、このドキュメントで定義されているプロトコル要素に適用されます。これは、新しいメソッド、ステータスコード、またはフィールドの定義など、HTTPを拡張するための既存のオプションには影響しません([HTTP]のセクション16を参照)。
拡張は、新しいフレームタイプ(セクション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)。
第5章完了!