この文書は「Hypertext Transfer Protocol version 2 (draft-ietf-httpbis-http2-16)」の日本語訳です。
原文の最新版 は、この日本語訳が参照した版から更新されている可能性があります。
原文はドラフト版であり、HTTP/2 は現在策定中の仕様であることに十分注意してください。
この日本語訳は参考情報であり、正式な文書ではないことにも注意してください。また、翻訳において生じた誤りが含まれる可能性があるため、必ず原文もあわせて参照することを推奨します。
draft-ietf-httpbis-http2-16
この仕様は、最適化された Hypertext Transfer Protocol (HTTP) のセマンティクス表現について説明します。HTTP/2 は、ヘッダーフィールドの圧縮を導入し、同一接続上の複数同時メッセージの実現により、ネットワークリソースのより効率的な利用とレイテンシの削減を可能にします。また、サーバーからクライアントへ一方的に送るプッシュ表現についても説明します。
この仕様は HTTP/1.1 のメッセージ構文を変更しますが、これを廃止するわけではありません。HTTP の既存のセマンティクスは変更しません。
この草案の議論は [1] にアーカイブされる HTTPBIS ワーキンググループのメーリングリスト ([email protected]) でおこなわれます。
ワーキンググループの情報は [2] で、HTTP/2 に関する情報は [3] でそれぞれ見つけることができます。
この草案における変更点は 付録B に要約されています。
このインターネット草案は BCP 78 と BCP 79 の規定に完全に準拠して提出されます。
インターネット草案は Internet Engineering Task Force (IETF) の作業文書です。他のグループも作業文書をインターネット草案として配布できることに注意してください。最新のインターネット草案のリストは http://datatracker.ietf.org/drafts/current/ にあります。
インターネット草案は、最長6ヶ月間有効な草案文書であり、いかなる時でも更新や置き換え、他の文書により廃止されることがあります。また、参考資料としてインターネット草案を使用したり、"進行中の作業" としてではなく引用をするのは不適切です。
このインターネット草案は2015年6月2日に期限切れとなります。
Copyright (c) 2014 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 Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.
Hypertext Transfer Protocol (HTTP) は広く成功したプロトコルです。しかしながら、HTTP/1.1 による下層のトランスポートの使い方 ([RFC7230]、6章) には、今日のアプリケーションのパフォーマンスに悪い影響を与える特性がいくつかあります。
特に、HTTP/1.0 は与えられた TCP 接続に対して、同時に1つのリクエストしか転送できません。HTTP/1.1 ではリクエストパイプラインが追加されましたが、それはリクエストの並列化に部分的に取り組んだだけで、今でも行頭ブロッキングに悩まされています。そのため、多数のリクエストを生成する必要がある HTTP/1.1 クライアントは、並行性やレイテンシを減らすために一般的にサーバーに対して複数の接続を使用します。
さらに、HTTP のヘッダーフィールドはしばしば重複し、冗長です。これは、巨大なネットワークパケットを多数生成し、不要なネットワークトラフィックを発生させるだけでなく、TCP [TCP] 輻輳の小さな初期ウインドウはすぐいっぱいになってしまいます。そして結果的に、1つの新しい TCP 接続上で複数のリクエストを発行すると、過度の待ち時間が発生することになります。
HTTP/2 では、基礎となる接続に対して HTTP セマンティクスの最適化マッピングを定義することによって、これらの問題に取り組みます。具体的には、同一接続上においてリクエストとレスポンスメッセージを交互に挟み込んだり、HTTP ヘッダーフィールドに対して効率のよい符号化方式を利用したりします。またリクエストの優先付けも可能にし、より重要なリクエストをより迅速に完了させることで更なる性能向上を実現します。
もたらされたプロトコルは、HTTP/1.x と比較して少ない TCP 接続を利用することになるため、よりネットワークフレンドリーになります。これは他のフローとの競合を減らし、接続寿命が長くなることを意味します。そして結果的に、利用可能なネットワークキャパシティの有効利用につながることになります。
最後に、HTTP/2 では、バイナリメッセージ構造を使用することで、メッセージ処理をより効率的にすることも可能にします。
HTTP/2 は HTTP セマンティクスの最適化された転送手段を提供します。HTTP/2 は HTTP/1.1 の主要な機能の全てに対応しますが、いくつかの方法を用いてより効率的なものを目指します。
HTTP/2 におけるプロトコルの基本的な単位はフレーム (4.1節) です。各フレームタイプは異なる目的を果たします。例えば、HEADERS と DATA フレームは HTTP リクエストとレスポンス (8.1節) の基礎を構成します。SETTINGS、WINDOW_UPDATE、PUSH_PROMISE といったその他のフレームタイプは他の HTTP/2 の機能に対応するために使われます。
リクエストの多重化は、各 HTTP リクエスト-レスポンスを単一のストリーム (5章) に割り当てることで実現します。ストリームは他のストリームとは独立しているため、リクエストのブロックや停止が、他のリクエストの進捗を妨げることはありません。
フロー制御や優先度付けは、多重化されたストリームを適切に使用できることを保証します。フロー制御 (5.2節) は、受信者が使用可能なデータのみが送信されることを保証するのに役立ちます。また、優先度付け (5.3節) は限られたリソースが最初の最も重要なリクエストに割り当てられることを保証します。
HTTP/2 では、サーバーがクライアントにレスポンスをプッシュすることができる、新しい対話モードを追加されます (8.2節)。サーバープッシュは、潜在的なレイテンシの増加に対してある程度のネットワーク使用率と引き換えに、サーバーがクライアントが必要とするデータを予測し、クライアントデータの送信を可能にします。サーバーは、PUSH_PROMISE フレームとしてリクエストを合成して送信し、プッシュをおこないます。その後、サーバーは合成したリクエストのレスポンスを別のストリーム上で送信できます。
コネクションで使用される HTTP ヘッダーフィールドには、多くの冗長なデータが存在する可能性があるため、それらを含むフレームは圧縮されます (4.3節)。これは、多くのリクエストを1つの TCP パケットに圧縮できるため、一般的なリクエストのサイズにおいて特に有益な効果があります。
HTTP/2 の仕様は4つのパートで構成されます:
フレーミングレイヤーやストリームレイヤーの概念の一部は HTTP から分離されていますが、この仕様では完全に汎用的なフレーミングレイヤーを定義するわけではありません。フレーミングレイヤーとストリームレイヤーは HTTP プロトコルとサーバープッシュの要件にあわせて作られました。
この文書のキーワード "MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"MAY"、そして "OPTIONAL" は RFC 2119 [RFC2119] で記述されたとおりに解釈されるべきです。
すべての数値はネットワークバイトオーダーです。特に断りがない限り、値は符号無しとなります。リテラルの値は、必要に応じて10進数または16進数で提供されます。また、16進数リテラルは10進数リテラルと区別するために "0x" ではじまります。
使用される用語は以下のとおりです:
最後に、"ゲートウェイ"、"中継者"、"プロキシ" そして "トンネル" は [RFC7230] の2.3節で定義されています。
HTTP/2 接続は TCP 接続の上で動作するアプリケーション層のプロトコルです ([TCP])。また、クライアントが TCP 接続を開始します。
HTTP/2 は、 HTTP/1.1 で使用されるのと同じ "http" と "https" の URI スキームを使用します。また、HTTP/2 は標準のポート番号も共有します: "http" 用の80番と、"https" 用の443番です。この結果、"http://example.org/foo" や "https://example.com/bar" といった対象リソース URI へのリクエストを処理する実装は、最初にアップストリームサーバー (クライアントがコネクションを確立しようとしているピア) が HTTP/2 に対応するかどうかを認識する必要があります。
これは HTTP/2 への対応を決定する手段が "http" と "https" の URI で異なることを意味します。"http" URI のための認識は3.2節で説明します。また、"https" URI のための認識は3.3節で説明します。
この文書で定義されるプロトコルの識別子は2つあります。
文字列 "h2" は TLS [TLS12] を使用する HTTP/2 プロトコルを識別します。この識別子は TLS Application layer protocol negotiation extension (ALPN) [TLS-APLN] フィールドや、TLS 上の HTTP/2 であることが識別されるいかなる場所において使用されます。
文字列 "h2" は、2つのオクテット 0x68, 0x32 として、ALPN プロトコル識別子にシリアライズされます。
文字列 "h2c" は平文の TCP 上での HTTP/2 プロトコルを識別します。 この識別子は HTTP/1.1 Upgrade ヘッダーフィールドや、TCP 上の HTTP/2 であることが識別されるいかなる場所において使用されます。
"h2" や "h2c" で通信するということは、この文書で説明される伝送方式、セキュリティ、フレーミング、メッセージセマンティクスを使用することを意味します。
[[CREF1: RFC 編集者注: この文書の最終版を公開する前に、この節の残りの部分は削除してください。]]
最終的な実装に限り、公開された RFC は自身を "h2" や "h2c" として識別できます。RFC が公開されるまでは、実装はこれらの文字を使用して自身を識別してはいけません (MUST NOT)。
この文書の文末までの用例や文章では、編集の利便性のために "h2" を使用します。草案版の実装では、この文字列を使用して識別してはいけません (MUST NOT)。
このプロトコルの草案版の実装は、"-" 文字と識別子として対応する草案番号を追加しなければなりません (MUST)。例えば、TLS 上の draft-ietf-httpbis-http2-11 は "h2-11" という文字列を使用して識別されます。
これらの草案版に基づく非互換の試験では、"-" 文字と実験名を識別子に追加しなければなりません (MUST)。例えば、draft-ietf-httpbis-http2-09 に基づく Packet mood-based encoding の実装実験では、"h2-09-emo" として自身を識別することになります。ラベルは [RFC7230] の3.2.6節で定義される "token" 構文に従わなければなりません (MUST)。実験をするにあたっては、[email protected] メーリングリストで各実験についての調整をすることをお勧めします。
次のホップの HTTP/2 への対応に関する事前知識なしに "http:" URI にリクエストをするクライアントは、HTTP アップグレードメカニズムを使用します ([RFC7230]、6.7節)。クライアントは "h2c" トークンを用いて HTTP/2 を指定した Upgrade ヘッダーフィールドを含む HTTP/1.1 リクエストを送信することで、これを実行します。この HTTP/1.1 リクエストには1つの HTTP2-Settings (3.2.1節) ヘッダーフィールドも含まなければなりません (MUST)。
例:
GET / HTTP/1.1 Host: server.example.com Connection: Upgrade, HTTP2-Settings Upgrade: h2c HTTP2-Settings: <HTTP/2 SETTINGS ペイロードの base64url エンコード>
エンティティボディを含むリクエストは、クライアントが HTTP/2 フレームを送信する前に、完全に送信されなければなりません (MUST)。これは、巨大なリクエストエンティティが完全に送信されるまで、そのコネクションの使用を妨げることを意味します。
最初のリクエストとその後に続くリクエストの並行性が重要な場合は、追加のラウンドトリップコストを負担して、HTTP/2 へのアップグレードを行う OPTIONS リクエストが使用できます。
HTTP/2 に対応しないサーバーは、リクエストに対して Upgrade ヘッダーフィールドが存在しなかったかのように応答できます。
HTTP/1.1 200 OK Content-Length: 243 Content-Type: text/html ...
サーバーは、Upgrade ヘッダーフィールドの "h2" は無視しなければなりません (MUST)。"h2" トークンの存在は TLS 上の HTTP/2 を意味し、3.3節で説明するようにネゴシエートされます。
HTTP/2 に対応するサーバーは 101 (Switching Protocols) レスポンスと共にアップグレードを受け入れます。101 レスポンスの終わりを示す空行の後、サーバーは HTTP/2 フレームの送信を開始できます。これらのフレームは Upgrade を開始したリクエストへのレスポンスを含まなければなりません (MUST)。
例:
HTTP/1.1 101 Switching Protocols Connection: Upgrade Upgrade: h2c [ HTTP/2 コネクション ...
サーバーにより送信される最初の HTTP/2 フレームは、サーバーコネクションプリフェイス (3.5節) として送信される SETTINGS フレーム (6.5節) でなければなりません (MUST)。101 レスポンスを受信すると、クライアントは SETTINGS フレームを含むコネクションプリフェイス (3.5節) を送信しなければなりません (MUST)。
アップグレードの前に送信された HTTP/1.1 リクエストには、ストリームID 1 が割り当てられ、可能な限りデフォルト優先度の値が割り当てられます。リクエストが HTTP/1.1 リクエストとして完了しているため、ストリーム 1 はクライアントからサーバーに対して暗黙的に half closed 状態になります。HTTP/2 接続を開始した後、ストリーム 1はレスポンスのために使用されます。
HTTP/1.1 から HTTP/2 にアップグレードするリクエストは、1つの "HTTP2-Settings" ヘッダーフィールドを送信しなければなりません (MUST)。"HTTP2-Settings" ヘッダーフィールドは、HTTP/2 接続を制御するパラメーターを含む接続固有ヘッダーフィールドです。このフィールドは、サーバーがアップグレードリクエストを受け付けることを見越して送信されます。
HTTP2-Settings = token68
このヘッダーフィールドが存在しなかったり、2つ以上存在するような場合、サーバーは接続を HTTP/ 2 にアップグレードしてはいけません (MUST NOT)。また、サーバーはこのヘッダーフィールドを送信してはいけません (MUST NOT)。
"HTTP2-Settings" ヘッダーフィールドの内容は、SETTINGS フレーム (6.5節) のペイロードであり、base64url (これは、最後の '=' を省略した [RFC4648] の5章で説明されている URL セーフかつファイル名セーフの Base64 エンコードです) 文字列としてエンコードされます。"token68" の ABNF [RFC5234] プロダクションは、[RFC7235] の2.1節に定義されています。
アップグレードは直接接続に対して適用することのみを意図しているため、"HTTP2-Settings" を送信するクライアントは、転送を防ぐために "Connection" ヘッダーフィールドの接続オプションとして "HTTP2-Settings" を送信しなければなりません (MUST) ([RFC7230]、6.1節)。
サーバーは他の SETTINGS フレームと同じように、これらの値をデコードし、解釈します。101 レスポンスは、暗黙的な応答としての役割を果たすため、明示的な SETTINGS パラメーターの応答 (6.5.3節) は不要です。このような値をアップグレードリクエストで提供することで、クライアントがサーバーからフレームを受信するよりも前に、パラメーターを送信できる機会を持てるようになります。
"https" URI へのリクエストをするクライアントは、 TLS [TLS12] と Application layer protocol negotiation extension [TLS-ALPN] を利用します。
TLS 上の HTTP/2 は "h2" アプリケーショントークンを使用します。"h2c" トークンはクライアントから送信されたり、サーバーにより選択されてはいけません (MUST NOT)。
TLS ネゴシエーションが完了すると、クライアントとサーバーはコネクションプリフェイス (3.5節) を送信しなければなりません (MUST)。
クライアントは、他の方法で特定のサーバーが HTTP/2 に対応していることを知ることができます。例えば、[ALT-SVC] では対応状況を通知するメカニズムを説明しています。
そのようなサーバーに対し、クライアントはコネクションプリフェイス (3.5節) を送信しなければなりません (MSUT)。また、続いて直ちに HTTP/2 フレームを送信してもよいものとします (MAY)。サーバーはコネクションプリフェイスの存在により、このような接続を識別できます。これは平文 TCP 上の HTTP/2 接続の確立にのみ影響し、TLS 上の HTTP/2 に対応する実装は、TLS のプロトコルネゴシエーション [[TLS-ALPN]] を使用しなければなりません (MUST)。
同様に、サーバーもコネクションプリフェイス (3.5節) を送信しなければなりません (MUST)。
追加情報がない、事前知識による HTTP/2 接続は、今後のコネクションに対しても指定されたサーバーが HTTP/2 に対応するという強いシグナルではありません。例えば、サーバーの設定の変更や、クラスター化されたサーバーインスタンス間で異なる設定をする、ネットワーク状況を変更するといったことは可能です。
HTTP/2 では、各エンドポイントはプロトコルの使用の最終確認と、HTTP/2 コネクションの初期設定を確立するために、コネクションプリフェイスを送信する必要があります。クライアントとサーバーはお互いに異なるコネクションプリフェイスを送信します。
クライアントコネクションプリフェイスは、24オクテットの配列ではじまり、16進数表現は以下のようになります (文字列表現: "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"):
0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
この配列の後には、SETTINGS フレーム (6.5節) が続かなければなりません (MUST)。この SETTINGS フレームは空であってもよいものとします (MAY)。101 Switching Protocols レスポンス (アップグレードの完了を示します) を受信した直後、もしくは TLS 接続の最初のアプリケーションデータのオクテットとして、クライアントはただちにクライアントコネクションプリフェイスを送信します。サーバーが対応するプロトコルを事前に知っていることによって HTTP/2 接続を開始する場合は、クライアントはコネクションを確立した直後にコネクションプリフェイスを送信します。
多数の HTTP/1.1 や HTTP/1.0 のサーバー、中継システムがさらにフレームを処理しないよう、このクライアントコネクションプリフェイスが選ばれました。これは、[TALKING] で提起された懸念には対応しないことに注意してください。
サーバーコネクションプリフェイスは空の可能性がある SETTINGS フレーム (6.5節) だけで構成され、HTTP/2 接続においてサーバーが送信する最初のフレームでなければなりません (MUST)。
ピアからコネクションプリフェイスの一部として受信した SETTINGS フレームは、コネクションプリフェイスの送信後にその適用を通知 (6.5.3節) しなけければなりません (MUST)。
不要なレイテンシを防ぐために、クライアントはクライアントコネクションプリフェイスの送信後、サーバーコネクションプリフェイスの受信を待たずに、すぐに追加のフレームをサーバーに送信することが認められています。しかしながら、サーバーコネクションプリフェイスの SETTINGS フレームが、クライアントがサーバーとどのように通信するかを変更するパラメーターを含む可能性があることに注意しないといけません。クライアントは、SETTINGS フレームを受信後に直ちにすべてのパラメーターに従うことが求められます。一部の構成においては、サーバーはこの問題を回避する機会を提供するため、クライアントが追加のフレームを送信するよりも前に SETTINGS を送信することが可能です。
クライアントとサーバーは、不正なコネクションプリフェイスを PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。ピアが HTTP/2 を使用していないことを不正なプリフェイスが示している場合は GOAWAY フレーム (6.8節) を省略してもよいものとします (MAY)。
HTTP/2 接続が確立されると、クライアントとサーバーはフレームの送信を開始できます。
全てのフレームは、9オクテット固定長のヘッダーから始まり、可変長のペイロードがその後に続きます。
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Length (24) | +---------------+---------------+---------------+ | Type (8) | Flags (8) | +-+-+-----------+---------------+-------------------------------+ |R| Stream Identifier (31) | +=+=============================================================+ | Frame Payload (0...) ... +---------------------------------------------------------------+ 図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/2 におけるヘッダーフィールドは、1つ以上の値が設定された名前です。これらは、HTTP リクエストとレスポンスのメッセージおよび、サーバープッシュ処理に使用されます (8.2節)。
ヘッダーリストは、0個以上のヘッダーフィールドからなる集合です。コネクションを通じて転送されるとき、ヘッダーリストは HTTP ヘッダー圧縮 [COMPRESSION] を使用してヘッダーブロックにシリアライズされます。シリアライズされたヘッダーブロックは、ヘッダーブロックフラグメントと呼ばれる1つ以上のオクテット列に分割され、HEADERS (6.2節)、 PUSH_PROMISE (6.6節)、または CONTINUATION (6.10節) フレームのペイロードとして転送されます。
Cookie ヘッダーフィールド [COOKIE] は HTTP マッピングにより特別に処理されます (8.1.2.4節)。
受信側エンドポイントはフラグメントを結合することでヘッダーブロックを再構築し、ヘッダーリストを復元するために伸張します。
完全なヘッダーブロックは以下のどちらかで構成されます:
ヘッダー圧縮は状態を持ちます。1つの圧縮コンテキストと1つの伸長コンテキストがコネクション全体で使用されます。各ヘッダーブロックは別々の単位として処理されます。ヘッダーブロックは、他の種類のフレームや他のストリームのフレームの間に挟み込まれずに、連続した一連のフレームとして送信されなければなりません (MUST)。一連の HEADERS や CONTINUATION フレームの最後のフレームには、END_HEADERS フラグが設定されていなければなりません (MUST)。また、一連の PUSH_PROMISE や CONTINUATION フレームの最後のフレームにも、END_HEADERS フラグが設定されていなければなりません (MUST)。これにより、ヘッダーブロックを論理的に単一のフレームと同等にできます。
ヘッダーブロックフラグメントは HEADERS、PUSH_PROMISE、CONTINUATION フレームのペイロードでのみ送信できます。これらのフレームは、受信者が保持する圧縮コンテキストを変更するデータを転送するためです。HEADERS、PUSH_PROMISE、CONTINUATION フレームを受信したエンドポイントは、フレームの破棄が発生したような場合であっても、ヘッダーブロックを再構築し、伸張しなければなりません (MUST)。ヘッダーブロックを伸張できない場合、受信者は COMPRESSION_ERROR コネクションエラー (5.4.1節) と共にコネクションを終了しなければなりません (MUST)。
"ストリーム" とは、HTTP/2 接続においてクライアントとサーバーとの間で交換されるフレームの独立した双方向シーケンスです。ストリームにはいくつかの重要な特徴があります:
ストリームのライフサイクルは、図1に示したようになります。
+--------+ 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: エンドポイントがこのフレームを送信 recv: エンドポイントがこのフレームを受信 H: HEADERS フレーム (CONTINUATION が続く可能性がある) PP: PUSH_PROMISE フレーム (CONTINUATION が続く可能性がある) ES: END_STREAM フラグ R: RST_STREAM フレーム 図2: ストリームの状態
このダイアグラムはストリームの状態遷移と、これらの遷移に影響するフレームとフラグのみを表していることに注意してください。なお、CONTINUATION フレームについては状態遷移をもたらさず、実質的に HEADERS や PUSH_PROMISE の一部になります。この目的のために、END_STREAM フラグはそれが設定されたフレームに対して別々のイベントとして処理され、END_STREAM フラグが設定された HEADERS フレームは2つの状態遷移を引き起こす可能性があります。
両方のエンドポイントは、それぞれの立場に応じたストリーム状態図を持ち、フレーム転送中では両者は異なるでしょう。エンドポイントはストリームの作成について互いに連携しません。ストリームはどちらかのエンドポイントにより一方的に作成されます。状態の不一致に伴う悪い影響は、RST_STREAM を送信した後の "closed" 状態に限定されます。その場合クローズ後にしばらくフレームを受信するかもしれません。
ストリームは次のような状態を持ちます:
全てのストリームは "idle" 状態からはじまります。この状態ではフレームは交換されません。
この状態では、次のような遷移が有効です:
この状態のストリームでの HEADERS や PUSH_PROMISE、PRIORITY 以外のフレームの受信は、PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。
"reserved (local)" 状態のストリームは、PUSH_PROMISE を送信して予約した状態です。PUSH_PROMISE フレームは、idle ストリームとリモートピアから始めた open ストリームを関連付けることによって、その idle ストリームを予約します (8.2節)。
この状態では、次のような遷移のみ可能です:
この状態において、エンドポイントは HEADERS や RST_STREAM、PRIORITY 以外のいかなる種類のフレームも送信してはいけません。(MUST NOT)。
PRIORITY または WINDOW_UPDATE フレームはこの状態で受信してもよいものとします (MAY)。この状態のストリームでの RST_STREAM や PRIORITY、WINDOW_UPDATE フレーム以外の受信については、PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。
"reserved (remote)" 状態のストリームは、リモートピアにより予約されています。
この状態では、次のような遷移のみ可能です:
エンドポイントは、予約済みストリームの優先度を変更するために、この状態で PRIORITY フレームを送信してもよいものとします (MAY)。また、エンドポイントはこの状態において、RST_STREAM や WINDOW_UPDATE、PRIORITY フレーム以外の種類のフレームを送信してはいけません (MUST NOT)。
この状態のストリームでの HEADERS や RST_STREAM、PRIORITY フレーム以外の受信については、PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。
"open" 状態のストリームは、両方のピアがいかなる種類のフレームを送信するために使用できます。この状態では、送信側のピアはストリームレベルのフロー制御 (5.2節) に従います。
この状態から、どちらのエンドポイントも END_STREAM フラグを設定したフレームを送信できます。それによって、ストリームは "half closed" 状態に遷移します。すなわちエンドポイントが END_STREAM フラグを送信すると、ストリームの状態は "half closed (local)" となり、エンドポイントが END_STREAM フラグを受信した場合は、ストリームの状態が "half closed (remote)" になります。
この状態では、どちらのエンドポイントも直ちに "closed" に遷移させる RST_STREAM フレームを送信できます。
"half closed (local)" のストリームは、フレームの送信に使用することはできません。この状態では、WINDOW_UPDATE や PRIORITY、RST_STREAM フレームのみを送信できます。
END_STREAM フラグを含むフレームを受信するか、いずれかのピアが RST_STREAM フレームを送信した時、ストリームはこの状態から "closed" に遷移します。
受信者は、END_STREAM フラグが設定されたフレームを送信した後の短時間に到着する可能性がある WINDOW_UPDATE をこの状態では無視できます。
この状態で受信する PRIORITY フレームは、現在のストリームに依存するストリームの再優先度付けに使用されます。
"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)。
END_STREAM フラグが含まれる DATA フレームや HEADERS フレームが送信された後の少しの間、WINDOW_UPDATE や RST_STREAM フレームをこの状態で受信できます。リモートピアが、RST_STREAM または END_STREAM フラグが設定されたフレームを受信し、処理するまでは、リモートピアがこれらのタイプのフレームを送信するかもしれません。エンドポイントは、この状態で受信した WINDOW_UPDATE や RST_STREAM フレームを無視しなければなりません (MUST)。しかしながら、エンドポイントは END_STREAM を送信した後かなり時間が経ってから到着したフレームを PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱うことを選択してもよいものとします (MAY)。
PRIORITY フレームは、依存するストリームの優先度付けのために closed ストリームに送信できます。エンドポイントは PRIORITY フレームを処理すべきです (SHOULD)。ただし、そのストリームが依存関係ツリー (5.3.4節) から削除された場合は無視できます。
もし RST_STREAM フレームを送信した結果としてこの状態に至った場合、RST_STREAM を受信したピアは、このストリームに対してフレームを既に送信していたり送信キューに入れていたりして、取りやめることができないかもしれません。エンドポイントは、RST_STREAM フレームを送信した後、closed ストリームで受信したフレームを無視しなければなりません (MUST)。エンドポイントは、この時点以降に到着したフレームを無視するか、エラーとして扱うかの期限を制限するかを選択してもよいものとします (MAY)。
RST_STREAM の送信後に受信したフロー制御下のフレーム (例: DATA) は、コネクションフロー制御のウインドウとして計算されます。これらのフレームは無視されるかもしれませんが、送信者が RST_STREAM を受信する前にフレームが送信されているため、送信者はコネクションフロー制御ウインドウを計算するようにこれらのフレームを考慮します。
エンドポイントは、RST_STREAM を送信した後に PUSH_PROMISE や CONTINUATION を受信するかもしれません。PUSH_PROMISE は関連付けられたストリームが終了されているかにかかわらず、ストリームを "reserved" に遷移させます。したがって、不要な予約済みストリームを終了するには RST_STREAM が必要になります。
この文書の他の場所でより具体的な指針が明記されていない場合、実装は、状態の説明において明示的に許可されていないフレームの受信を PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱うべきです (SHOULD)。なお、PRIORITY は全てのストリームの状態において送信や受信がされる可能性があることに注意してください。不明な種類のフレームは無視されます。
HTTP リクエスト/レスポンスの交換における状態遷移の例は、8.1節で確認できます。サーバープッシュの状態遷移の例は、8.2.1節と8.2.2節で確認できます。
ストリームは、符合なし31ビットの整数で識別されます。クライアントが開始したストリームは奇数のストリームIDを使わなければなりません (MUST)。また、サーバーが開始したストリームは偶数のストリームIDを使わなければなりません (MUST)。ストリームID 0 (0x0) は、コネクション制御メッセージに使用されます。ストリームID 0 は新しいストリームの確立には使用できません。
HTTP/2 にアップグレードする HTTP/1.1 リクエスト (3.2節) には、ストリームID 1 (0x1) で応答されます。アップグレードの完了後、ストリーム 0x1 はクライアントに対して "half closed (local)" になります。したがって、HTTP/1.1 からアップグレードするクライアントが、ストリーム 0x1 を新しいストリームIDとして選択することはできません。
新しく確立されるストリームIDは、エンドポイントがすでに開始または予約した全てのストリームよりも大きい数値でなければなりません (MUST)。この影響を受けるのは、HEADERS フレームを使用して開始されたストリームと、PUSH_PROMISE を使用して予約されたストリームです。予期せぬストリームIDを受信したエンドポイントは、PROTOCOL_ERROR タイプのコネクションエラー (5.4.1節) を返さなければなりません (MUST)。
新しいストリームIDを利用すると、それより小さいストリームIDで "idle" 状態のストリームを全て暗黙的に終了します。例えば、クライアントがストリームID 5 のフレームを送信することなくストリームID 7 の HEADERS フレームを送信した場合、ストリームID 7 のフレームを最初に送受信した時点で、ID 5 のストリームは "closed" 状態に遷移します。
ストリームIDは再利用できません。長時間のコネクションでは、エンドポイントがストリームIDの利用可能な範囲を越えてしまう可能性があります。新しいストリームIDを生成できないクライアントは、新しいストリームのために新たなコネクションを確立できます。新しいストリームIDを確立できないサーバーは、新しいストリームのために新しいコネクションを開始することをクライアントに強制するために、GOAWA フレームを送信できます。
ピアは、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)。SETTINGS_MAX_CONCURRENT_STREAMS を現在の同時ストリーム数よりも少ない値に設定したいエンドポイントは、新しい値を超えるストリームを終了するか、完了させることができます。
ストリームの多重化を使用すると、TCP 接続を使用する上で競合が発生し、その結果ストリームのブロックが起こります。フロー制御の仕組みは、同一コネクション上でストリームが互いに破壊的な干渉をしないことを保証します。フロー制御は、個々のストリームとコネクション全体のどちらにも使用されます。
HTTP/2 では、WINDOW_UPDATE フレーム (6.9節) の使用を通じて、フロー制御を提供します。
HTTP/2 のストリームフロー制御は、プロトコルの変更の必要なしに、様々なフロー制御アルゴリズムを適用することを目標にしています。HTTP/2 におけるフロー制御は以下のような特徴があります:
装には、優先度に基づいてリクエストやレスポンスを送信する方法の管理や、リクエストの行頭ブロッキングを防ぐ方法の選択、新しいストリームの作成の管理などをする責任があります。これらのアルゴリズムの選択肢は、フロー制御アルゴリズムと相互に影響します。
フロー制御は、リソース制限下で動作しているエンドポイントを保護するために定義されています。例えばプロキシは、多くのコネクションの間でメモリーを共有する必要があり、そこには低速なアップストリームや高速なダウンストリームを含む可能性があるでしょう。フロー制御は、受信者があるストリームのデータの処理ができない状況であっても、同一コネクション上の他のストリームの処理を継続したい場合に対応します。
この機能を必要としない構成では、新しいデータを受信した際に利用可能な容量を増加させるように最大サイズのフロー制御ウインドウを告知できます。これはそのような受信者において実質的にフロー制御を無効化します。反対に、送信者は常に受信者により通知されたフロー制御ウインドウの影響を受けます。
リソース (例えばメモリーなど) が制限された構成では、ピアが使用するメモリーの量を制限するために、フロー制御を使用できます。しかしながら、帯域幅遅延積 ([RFC7323]) についての知識なしにフロー制御を有効化した場合、利用可能なネットワークリソースを適切に利用できない可能性があることに注意してください。
最新の帯域幅遅延積についての十分な知識があるとしても、フロー制御の実装は困難である可能性があります。フロー制御を使用する時、受信者は TCP の受信バッファを直ちに読み込まなければなりません (MUST)。読み込みに失敗すると、WINDOW_UPDATE などの重要なフレームの読み込みと処理ができず、デッドロックを引き起こす可能性があります。
クライアントは、ストリームを開始する HEADERS フレーム (6.2節) に優先度情報を含めることで、新しいストリームの優先度を指定できます。PRIORITY フレーム (6.3節) を使用すれば、いつでもストリームの優先度を変更できます。
優先度の目的は、エンドポイントが同時ストリームを管理する際に、そのピアに対してリソースの割り当て方法を明示できるようにすることです。最も重要なのは、送信キャパシティが限られている時に、フレームを転送するストリームを選択するために優先度が使用できることです。
ストリームは、他のストリームの完了 (5.3.1節) に依存する関係を作ることで、優先度を設定できます。各依存関係には、相対的な重みが割り当てられ、その値は、同じストリームに依存するストリームに割り当てられた利用可能なリソースの、相対的な比率を決定するために使用されます。
ストリームの優先度を明示的に設定することは、優先度付け処理への入力になります。これは他のストリームに相対するストリームに対して、特別な処理や転送順序を保証するものではありません。エンドポイントは優先度を使用して、ピアに特定の順序による同時ストリームの処理を強制できません。優先度を明示することは、あくまで提案でしかありません。
優先度情報の提供は任意です。特に指示がない場合は、デフォルトの値が使用されます (5.3.5節)。
各ストリームは他のストリームに明示的な依存関係を与えることができます。依存関係を含めることで、依存ストリームよりも指定されたストリームへのリソースの割り当てが優先されることを表現します。
他のストリームに依存しないストリームには 0x0 のストリーム依存関係が与えられます。言い換えれば、存在しないストリーム 0 はツリーのルートを構成します。
他のストリームの依存するストリームは依存ストリームです。ストリームが依存する先のストリームは、親ストリームとなります。"idle" 状態にあるストリームなど、現在ツリーにないストリームへの依存は、そのストリームにデフォルト優先度が与えられることになります。
ストリームを他のストリームの依存関係に割り当てるとき、そのストリームは、親ストリームの新しい依存関係として追加されます。同じ親を共有する依存ストリームは、その順序をお互いに考慮しません。例えば、ストリームBとCがストリームAに依存する時、ストリームAを依存先とするストリームDが生成された場合、Aの依存関係は任意の順序でB、C、Dが続きます。
A A / \ ==> /|\ B C B D C 図3: デフォルト依存関係の生成例
排他フラグは依存関係に新しい階層を挿入できます。排他フラグは、親ストリームの依存関係を自身の依存関係となるようにし、さらに自身を親ストリームの唯一の依存関係となるようにします。先ほどの例において、ストリームAに対して排他依存関係と共にストリームDを生成した場合、DはBとCの親の依存関係になります。
A A | / \ ==> D B C / \ B C 図4: 排他依存の生成例
依存ツリーの内部では、全ての依存先のストリーム (0x0までの親ストリームのつながり) が終了したり、ストリームの続行が不可能であった場合でも、依存ストリームにはリソースが割り当てられるべきです (SHOULD)。
ストリームは自身に依存できません。エンドポイントはこれを PROTOCOL_ERROR のストリームエラー (5.4.2節) として扱わなければなりません (MUST)。
全ての依存ストリームには、1から256までの整数の重みが割り当てられます。
同じ依存関係にあるストリームは、それらの重みに比例してリソースが割り当てられるべきです (SHOULD)。例えば、ストリームAに依存するストリームBの重みが4であり、同じストリームAに依存するストリームCの重みが12であった場合、Aに何も進展がなければ、ストリームBにはストリームCに割り当てられたリソースの3分の1が割り当てられます。
ストリームの優先度は PRIORITY フレームの使用により変更されます。依存関係を設定すると、ストリームを指定した親ストリームに依存させます。
親ストリームが再優先度付けされた場合、依存ストリームは親ストリームと共に移動します。再優先度付けされたストリームに排他フラグを伴う依存関係を設定すると、新しい親ストリームの全ての依存関係を、自身の依存関係になるように移動します。
ストリームが自身に依存するストリームの1つに依存関係を生成する場合、以前の依存ストリームは最初に再優先度付けされるストリームの前の親の依存関係になるように移動します。移動する依存ストリームはその重みを維持します。
例えば、BとCがAに、DとEがCに、FがDに依存する依存ツリーを考えます。AがDに依存関係を生成する場合、DはAの位置に移動します。Fを除く他の全ての依存関係はとどまり、再優先度付けが排他である場合は、全てがAに依存するようになります。
? ? ? ? | / \ | | A D A D D / \ / / \ / \ | B C ==> F B C ==> F A OR A / \ | / \ /|\ D E E B C B C F | | | F E E (中間状態) (非排他的状態) (排他的状態) 図5: 依存関係の並び替えの例
ストリームが依存ツリーから削除された際、その依存関係は終了したストリームの親ストリームに移動できます。新しい依存関係における重みは、自身の重みに基づき、終了したストリームの依存関係の重みに比例して再計算されます。
依存ツリーから削除されたストリームは、一部の優先度情報が失われる可能性があります。リソースは、同じ親ストリームを持つストリーム間で共有されます。これは、そのセット内のストリームが終了するか、ブロックされた状態になった場合、ストリームに割り当てられた予備のリソースはすぐ隣同士のストリームに分散されることを意味します。しかしながら、共有の依存関係がツリーから削除された場合、それらのストリームは、次の上位レベルのストリームとリソースを共有します。
例えば、まずストリームAとBが親を共有しており、ストリームCとDの両方がストリームAに依存していると仮定します。ストリームAとDの処理が続行できない場合は、ストリームAを削除する前に、ストリームCがAのためのリソースの全てを受け取ります。もしストリームAがツリーから削除された場合、ストリームAの重みはストリームCとDに均等に分割されます。ストリームDがまだ処理を続行できない場合、結果としてストリームCは少なくなったリソース比率を受け取ることになります。ストリームCは利用可能なリソースの半分ではなく、3分の1を受け取ります。
ストリームの依存関係を生成する優先度情報が転送中でも、そのストリームを終了することは可能です。依存関係に指定されたストリームが関連する優先度情報を持っていない場合、その依存ストリームには代わりにデフォルト優先度 (5.3.5節) が割り当てられます。ストリームには意図したよりも異なる優先度が与えられるため、最適でない優先度が設定される可能性があります。
これらの問題を防ぐために、エンドポイントは、ストリームが終了した後しばらくの間、ストリームの優先度状態を保持すべきです (SHOULD)。長く状態が保持されると、低確率でストリームが不正に割り当てられたり、デフォルトの優先度が割り当てられたりしてしまいます。
同様に、"idle" 状態にあるストリームは優先度が割り当てられたり、他のストリームの親になることができます。これにより、依存ツリー内に優先度をより柔軟に表現できるグルーピングノードを作成できます。別のストリームの親になる idle ストリームには、デフォルト優先度 (5.3.5節) が割り当てられます。
SETTINGS_MAX_CONCURRENT_STREAMS により設定される制限に計算されないストリームの優先度情報の保持は、エンドポイントに大きな状態負荷を生む可能性があります。従って、保持される優先度状態の量を制限してもよいものとします (MAY)。
エンドポイントが優先度のために管理する追加の状態量は、負荷に依存する可能性があります。高負荷時では、リソースのコミットメントを制限するために優先度の状態を破棄できます。極端なケースでは、エンドポイントは有効なストリームや予約済みストリームの優先度も破棄できます。固定の上限が適用された場合、エンドポイントは少なくとも SETTINGS_MAX_CONCURRENT_STREAMS で許可されたストリームよりも多くの状態を保持すべきです (SHOULD)。実装は、優先度ツリーにおいて活発に使用されるストリームの状態の保持を試みるべきです (SHOULD)。
終了したストリームの優先度を変更する PRIORITY フレームを受信したエンドポイントは、十分な状態を保持しているのであれば、そのストリームに依存するストリームの重みを変更すべきです (SHOULD)。
優先度情報の提供は任意です。ストリームにはストリーム 0x0 への非排他的依存がデフォルトで割り当てられます。プッシュストリーム (8.2節) は関連付けられたストリームに依存します。どちらの場合も、ストリームにはデフォルトの重み 16 が割り当てられます。
HTTP/2 の枠組みにおいては、2種類のエラーを認めています:
エラーコードのリストは7章にあります。
コネクションエラーとは、フレーミングレイヤーの処理の妨げとなるエラーや、接続状態を破壊するエラーです。
コネクションエラーが発生したエンドポイントは、ピアから受信に成功した最後のストリームIDと共に GOAWAY フレーム (6.8節) を最初に送信するべきです (SHOULD)。GOAWAY フレームにはコネクションが終了した理由を示すエラーコードが含まれます。エラー状態での GOAWAY フレームの送信後は、エンドポイントは TCP 接続を終了しなければなりません (MUST)。
GOAWAY は受信側エンドポイントで期待通りに受信されない可能性があります ([RFC7230]、6.6節)。コネクションエラーが発生した場合、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)。
ストリームが開かれている間、または half closed 状態の間に TCP 接続が終了または初期化された場合、エンドポイントはストリームが異常終了し、不完全な状態にあると見なさなければなりません (MUST)。
HTTP/2 はプロトコルの拡張を認めています。プロトコル拡張はこの節で説明する制限の範囲内で、追加のサービスの提供やプロトコルの様々な面を変更するために使用できます。拡張は単一の HTTP/2 コネクションの範囲に影響します。
拡張では、新しいフレームタイプ (4.1節)、新しい設定 (6.5.2節)、新しいエラーコード (7章) の使用が認められています。レジストリはこれらの拡張ポイントを管理するために、フレームタイプ (11.2節)、設定 (11.3節)、エラーコード (11.4節) でそれぞれ制定されています。
実装は、全てのプロトコルの拡張要素における不明また未対応の値を無視しなければなりません (MUST)。実装は不明または未対応のタイプのフレームを破棄しなければなりません (MUST)。これはどの拡張ポイントも、事前の合意やネゴシエートなしに拡張によって安全に使用できることを意味します。しかしながら、ヘッダーブロック (4.3節) の間に現れる拡張フレームは許可されません。これらは PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱われなければなりません (MUST)。
既存のプロトコル構成要素のセマンティクスを変更する拡張は、使用される前にネゴシエートされなければなりません (MUST)。例えば、HEADERS フレームの配置を変更する拡張は、ピアからこれを受け入れる肯定的な通知があるまで使用することはできません。このような場合、レイアウトの変更が有効になった時に調整を必要とする可能性があります。DATA フレーム以外のフレームをフロー制御の対象として扱う場合は、そのようにセマンティクスを変更し、ネゴシエーションを通じてのみ完了できることに注意してください。
この文書では、拡張の使用をネゴシエートする具体的な方法を強制しません。しかし、設定 (6.5.2節) がこのような目的で使用されることに注意してください。もし両方のピアが拡張を使用する意図を示す値を設定した場合は、その拡張は使用されます。拡張のネゴシエーションに設定が使用される場合、その初期値はその拡張が無効になるように定義されなければなりません (MUST)。
この仕様では、一意な8ビットのタイプコードで識別される、いくつかのフレームタイプを定義します。各フレームタイプは、全体的なコネクションや個々のストリームの確立と管理について、それぞれ異なる目的を果たします。
特定のフレームタイプの送信は、コネクションの状態を変更できます。エンドポイントの両方が接続状態を同期し続けることに失敗した場合、そのコネクションにおいてこれ以上正常な通信をすることはできません。したがって、エンドポイントは特定のフレームを使用することで、状態にどのような影響を与えるかの共通理解を持つことが重要です。
DATA フレーム (type=0x0) は、ストリームに関連する任意の可変長オクテット列を転送します。HTTP リクエストまたはレスポンスのペイロードを伝えるために、1つ以上の DATA フレームが使用されます。
DATA フレームは任意のパディングを含んでもよいものとします (MAY)。パディングは DATA フレームのメッセージサイズを隠すために追加できます。
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Pad Length? (8)| +---------------+-----------------------------------------------+ | Data (*) ... +---------------------------------------------------------------+ | Padding (*) ... +---------------------------------------------------------------+ 図6: DATA フレームペイロード
DATA フレームは以下のフィールドを含みます:
DATA フレームは以下のフラグを定義します:
DATA フレームはストリームに関連付けられなければなりません (MUST)。Stream Identifier フィールドが 0x0 の 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オクテット大きくできます。
パディングはセキュリティのための機能です。10.7節を参照してください。
HEADERS フレーム (type=0x1) は名前-値のペアを転送します。これはストリームの開始 (5.1節) に使用されます。HEADERS フレームは "open" または "half closed (remote)" 状態のストリームに送信できます。
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Pad Length? (8)| +-+-------------+-----------------------------------------------+ |E| Stream Dependency? (31) | +-+-------------+-----------------------------------------------+ | Weight? (8) | +-+-------------+-----------------------------------------------+ | Header Block Fragment (*) ... +---------------------------------------------------------------+ | Padding (*) ... +---------------------------------------------------------------+ 図7: HEADERS フレームペイロード
HEADERS フレームのペイロードは以下のフィールドを含みます:
HEADERS フレームは以下のフラグを定義します:
HEADERS フレームのペイロードは、ヘッダーブロックフラグメント (4.3節) を含みます。HEADERS フレームに収まらないヘッダーブロックは CONTINUATION フレーム (6.10節) に分割されなければなりません。
HEADERS フレームはストリームに関連付けられなければなりません (MUST)。受信した HEADERS フレームの Stream Identifier フィールドが 0x0 であった場合、受信者は PROTOCOL_ERROR のコネクションエラー (5.4.1節) として応答しなければなりません (MUST)。
HEADERS フレームは、4.3節で定義されたように接続状態を変更します。
HEADERS フレームは任意のパディングを含みます。Padding フィールドと関連するフラグは DATA フレーム (6.1節) における定義と全く同じです。
HEADERS フレームの優先度情報は、PRIORITY フレームで送信されるものと論理的には同じですが、HEADERS に含めることで新しいストリームが作られた際にストリームの優先度が混乱するのを防止できます。
PRIORITY フレーム (type=0x2) は、送信者からのストリーム優先度 (5.3節) を指定します。このフレームは、アイドル中のストリームや終了したストリームを含む既存のストリームに対していつでも送信できます。
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |E| Stream Dependency (31) | +-+-------------+-----------------------------------------------+ | Weight (8) | +-+-------------+ 図8: PRIORITY フレームペイロード
PRIORITY フレームのペイロードは、以下のフィールドを含みます:
PRIORITY フレームはフラグを定義しません。
PRIORITY フレームは既存のストリームに関連付けられます。ストリームIDが 0x0 の PRIORITY フレームを受信した場合、受信者は PROTOCOL_ERROR のコネクションエラー (5.4.1節) として応答しなければなりません (MUST)。
PRIORITY フレームは、全ての状態のストリームに送信できます。ただし、1つのヘッダーブロック (4.3節)を構成する連続したフレームの間での送信はできません。このフレームは、処理の完了後やフレーム送信後に受信されることもあり、そのため現在のストリームには何も影響を与えない可能性があることに注意してください。"half closed (remote)" や "closed" 状態にあるストリームでは、このフレームは現在のストリームの処理にのみ影響し、ストリームの送信には影響を与えません。
PRIORITY フレームは "idle" または "closed" 状態にあるストリームに送信できます。これは、未使用または終了済みの親ストリームの優先度を変更することで、依存ストリームのグループの再優先度付けを可能にします。
長さが5オクテットでない PRIORITY フレームは、FRAME_SIZE_ERROR のストリームエラー (5.4.2節) として扱われなければなりません (MUST)。
RST_STREAM フレーム (type=0x3) はストリームの即時終了を可能にします。RST_STREAM はストリームのキャンセルの要求やエラーの状態にあることを示すために送信されます。
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Error Code (32) | +---------------------------------------------------------------+ 図9: RST_STREAM フレームペイロード
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 フィールドが 0x0 であった場合、受信者は 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=0x4) は、ピアの振る舞いに関する初期設定や制約といった、エンドポイントの通信方法に影響を与える設定パラメーターを転送します。SETTINGS フレームはそのようなパラメータの受信確認にも使用されます。SETTINGS パラメーターはそれぞれが「設定」としても呼ばれます。
SETTINGS パラメーターはネゴシエートされません。これらは送信側ピアが特性を記述し、受信側ピアによって使用されます。また、それぞれのピアから、同一のパラメーターに対して異なる値が通知されます。例えば、クライアントは高い初期フロー制御ウインドウを設定するかもしれませんが、サーバーはリソースを節約するために低い値を設定するかもしれません。
SETTINGS フレームは、コネクション開始時に両方のエンドポイントから送信されなければなりません (MUST)。また、接続中はいかなる時でもいずれかのエンドポイントから送信してもよいものとします (MAY)。実装は、この仕様に定義されている全てのパラメーターに対応しなければなりません (MUST)。
SETTINGS フレームの各パラメーターは、そのパラメーターの既存の値を置き換えます。パラメーターは登場した順序で処理され、SETTINGS フレームの受信者は現在のパラメーター値以外の状態を維持する必要はありません。したがって SETTINGS パラメーターの値は受信者が最後に処理した値になります。
SETTINGS パラメーターは受信したピアにより確認されます。これを有効にするため、SETTINGS フレームは以下のフラグを定義します:
SETTINGS フレームは、1つのストリームではなく、コネクションに対して常に適用されます。SETTINGS フレームのストリームIDは 0 (0x0) でなければなりません (MUST)。Stream Identifier フィールドに 0x0 以外の値が設定された 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ビットの設定値からなります。
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identifier (16) | +-------------------------------+-------------------------------+ | Value (32) | +---------------------------------------------------------------+ 図10: 設定フォーマット
定義済みの設定は以下の通りです:
不明や未対応の識別子を含む SETTINGS フレームを受信したエンドポイントは、その設定を無視しなければなりません (MUST)。
ほとんどの SETTINGS 値にとって、いつピアが変更するパラメーター値を受信し、その値を適用したかを知ることはメリットになり、そうなることが求められます。このような同期点を提供するために、ACK フラグが設定されていない SETTINGS フレームの受信者は、受信後に更新されたパラメーターを可能な限り早く適用しなければなりません (MUST)。
SETTINGS フレームの値は、その間に他のフレームを処理することなく、出現した順序で処理されなければなりません (MUST)。未対応のパラメーターは無視されなければなりません (MUST)。全ての値を処理後、受信者は ACK フラグを設定した SETTINGS フレームをすぐに送信しなければなりません (MUST)。ACK フラグが設定された SETTINGS フレームを受信すると、パラメーターを変更した送信者は適用された設定に依存できます。
SETTINGS フレームの送信者が妥当な時間に応答を受信しなかった場合、SETTINGS_TIMEOUT のコネクションエラー (5.4.1節) として応答してもよいものとします (MAY)。
PUSH_PROMISE フレーム (type=0x5) は、送信者が開始する予定のストリームを事前にピアエンドポイントに通知するために使用します。PUSH_PROMISE フレームは、エンドポイントがストリームに追加のコンテキストを提供するヘッダーセットと共に、作成する予定のストリームの符号なし31ビット識別子を含みます。PUSH_PROMISE フレームの使用についての完全な説明は、8.2節に記述されています。
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Pad Length? (8)| +-+-------------+-----------------------------------------------+ |R| Promised Stream ID (31) | +-+-----------------------------+-------------------------------+ | Header Block Fragment (*) ... +---------------------------------------------------------------+ | Padding (*) ... +---------------------------------------------------------------+ 図11: PUSH_PROMISE ペイロードフォーマット
PUSH_PROMISE フレームのペイロードは、以下のフィールドを含みます:
PUSH_PROMISE フレームは以下のフラグを定義します:
PUSH_PROMISE フレームは既存のピアが開始したストリームに関連付けられなければなりません (MUST)。PUSH_PROMISE フレームのストリームIDは、そのストリームが関連付けられたものであることを示します。ストリームIDフィールドに 0x0 を指定した場合、受信者は 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" 状態に遷移させることで、今後使用するストリームを予約します。送信者は、"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節) (これはつまり、現在 "idle" 状態でないストリームのIDを指します) を予約する PUSH_PROMISE への応答も、PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。
PUSH_PROMISE フレームは任意のパディングを含みます。Padding フィールドと関連するフラグは DATA フレーム (6.1節) における定義と全く同じです。
PING フレーム (type=0x06) は、アイドル中のコネクションがまだ機能しているかどうかを確認するだけでなく、送信者からの往復遅延時間も計測するための仕組みです。PING フレームはどちらのエンドポイントも送信できます。
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | Opaque Data (64) | | | +---------------------------------------------------------------+ 図12: PING ペイロードフォーマット
PING フレームは、フレームヘッダーに加え、ペイロードに8オクテットのデータを含まなければなりません (MUST)。送信者はペイロードに任意の値を選択して含めることができ、任意の方法でそれらのオクテットを使用できます。
ACK フラグを含まない PING フレームの受信者は、そのレスポンスとして、同じペイロードと共に ACK フラグを設定した PING フレームを送信しなければなりません (MUST)。PING レスポンスは他のフレームよりも高い優先度が設定されるべきです (SHOULD)。
PING フレームは以下のフラグを定義します:
PING フレームは個別のストリームには関連付けられません。ストリームIDフィールドの値が 0x0 でない PING フレームを受信した場合、受信者は PROTOCOL_ERROR のコネクションエラー (5.4.1節) として応答しなければなりません (MUST)。
長さフィールドの値が8になっていない PING フレームの受信者は、FRAME_SIZE_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません (MUST)。
GOAWAY フレーム (type=0x7) は、リモートピアがコネクションにおけるストリームの作成を終了することを伝えます。GOAWAY フレームはクライアントとサーバーのどちらからでも送信できます。このフレームが送信されると、送信者は、最終ストリームIDに指定した値よりも大きいストリームIDをもつ、新しいストリームに送信されたフレームを無視します。GOAWAY フレームの受信者は、現在のコネクション上で新しい追加のストリームを開始してはいけません (MUST NOT)。しかし、新しいストリームを生成するために新しくコネクションを確立できます。
このフレームの目的は、以前確立したストリームの処理を終了している間であっても、エンドポイントが新しいストリームの受け入れを適切に停止できるようにすることです。これによりサーバーメンテナンスのような管理操作を可能にします。
新しくストリームを開始したエンドポイントと、GOAWAY フレームを送信したリモートの間には、固有の競合状態があります。このような場合に対処するため、GOAWAY は現在のコネクションで送信側エンドポイントが最後に処理した、または処理したと思われる、ピアが開始した最後のストリームIDを含みます。例えば、サーバーが GOAWAY フレームを送信した場合、最後のストリームIDは、クライアントが開始したストリームの最も大きい番号のストリームIDになります。
GOAWAY の受信者が、GOAWAY フレームで示されたストリームIDよりも大きいIDを持つストリームにデータを送信した場合、それらのストリームは処理されません。GOAWAY フレームの受信者は、そのストリームの全てが生成されなかったものとして扱うことができます。したがって、これらのストリームは、後に新しいコネクション上で再施行できます。
ストリームが部分的に処理されたのかどうかを、リモートが知ることができるよう、エンドポイントはコネクションを終了する前に、常に GOAWAY フレームを送信するべきです (SHOULD)。例えば、ある HTTP クライアントが、サーバーがコネクションを終了するのと同時に POST を送信した場合に、サーバーがどのストリームまで処理したかを示す GOAWAY フレームを送信しなければ、クライアントはサーバーが POST リクエストの処理を開始したのかどうかを知ることができません。
不正なピアに対しては、エンドポイントは GOAWAY の送信なしにコネクションを終了することを選ぶかもしれません。
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |R| Last-Stream-ID (31) | +-+-------------------------------------------------------------+ | Error Code (32) | +---------------------------------------------------------------+ | Additional Debug Data (*) | +---------------------------------------------------------------+ 図13: GOAWAY ペイロードフォーマット
GOAWAY フレームはフラグを定義しません。
GOAWAY フレームは特定のストリームではなく、コネクションに対して適用されます。エンドポイントはストリームIDが 0x0 以外の値になっている 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 フレームを送信できます。これにより、リクエストを失うことなく、正しくコネクションが終了されることを確実にします。
GOAWAY フレームの送信後、送信者は最終ストリームに指定したIDよりも大きいIDを持つストリームのフレームを破棄することができます。しかしながら、接続状態を変更するフレームは完全には無視されません。例えば、HEADERS、PUSH_PROMISE、CONTINUATION フレームは、矛盾のないヘッダー圧縮の状態 (4.3節) を保証するために、最低限処理されなければなりません (MUST)。同様に、DATA フレームはコネクションフロー制御ウインドウに対して計算されなければなりません (MUST)。これらのフレームの処理に失敗すると、フロー制御やヘッダー圧縮の状態が同期されない可能性があります。
GOAWAY フレームは、コネクションを終了する理由を示す32ビットのエラーコード (7章) も含みます。
エンドポイントは、GOAWAY フレームのペイロードに未定義のデータを追加してもよいものとします (MAY)。デバッグ情報にはセキュリティやプライバシーに関わるデータを含めることができます。記録されていたり、永続的に格納されているデバッグデータは、不正なアクセスを防ぐために適切な保護手段を持たなければなりません (MUST)。
WINDOW_UPDATE フレーム (type=0x8) フロー制御を実行するために使用されます。概要については5.2節を参照してください。
フロー制御は、個々のストリームとコネクション全体の2段階でおこなわれます。
どちらの段階のフロー制御もホップ間、つまり2つのエンドポイントの間でのみおこなわれます。中継者は繋がっているコネクションの間で WINDOW_UPDATE フレームを転送しません。しかしながら受信者がデータ転送をスロットリングすることによって、元の送信者に対してフロー制御情報を間接的に伝搬させることができます。
フロー制御は、フロー制御の対象となる特定のフレームにのみ適用されます。この文書に定義されるフレームの種類のうち、対象となるのは DATA フレームのみです。フロー制御の対象でないフレームは、受信者がフレームを処理するためのリソースの割り当てに失敗しない限り、受け入れ、処理されなければなりません (MUST)。フレームの受け入れに失敗した場合、受信者はストリームエラー (5.4.2節) または FLOW_CONTROL_ERROR のコネクションエラー (5.4.1節) として応答してもよいものとします (MAY)。
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |R| Window Size Increment (31) | +-+-------------------------------------------------------------+ 図14: WINDOW_UPDATE ペイロードフォーマット
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 フレームを受信した送信者は、フレームに指定された容量を使用して、関連するウインドウを更新します。
送信者は、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 フレームは、現在の全てのストリームの初期フロー制御ウインドウサイズを変更できます。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 フレームの送信後、受信者にはフロー制御の制限を超えたストリームの処理について、2つの選択肢があります:
CONTINUATION フレーム (type=0x9) は連続するヘッダーブロックフラグメントの続きに使用されます (4.3節)。同一ストリームの直前のフレームが END_HEADERS が設定されていない HEADERS、PUSH_PROMISE、または CONTINUATION である限り、任意の数の CONTINUATION フレームを既存のストリームに送信できます。
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Header Block Fragment (*) ... +---------------------------------------------------------------+ 図15: CONTINUATION フレームペイロード
CONTINUATION フレームのペイロードはヘッダーブロックフラグメントを含みます (4.3節)。
CONTINUATION フレームは以下のフラグを定義します:
CONTINUATION フレームは4.3節で定義されるように接続状態を変更します。
CONTINUATION フレームはストリームに関連付けられなければなりません (MUST)。ストリームIDフィールドの値が 0x0 になっている 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/1.1 セマンティクスの仕様や要件、コンテンツ [RFC7231]、条件付きリクエスト [RFC7232]、範囲リクエスト [RFC7233]、キャッシュ [RFC7234] と認証 [RFC7235] は HTTP/2 に適用できます。HTTP や HTTPS URI スキームのような HTTP/1.1 メッセージ構文とルーティング [RFC7230] の一部も HTTP/2 に適用できますが、このプロトコル専用のセマンティクスの表現は、以降の節で定義されます。
クライアントは、過去に使用していないストリームID (5.1.1節) を使用して、新しいストリーム上で HTTP リクエストを送信します。サーバーはリクエストと同一のストリーム上で HTTP レスポンスを送信します。
HTTP メッセージ (リクエストやレスポンス) はそれぞれ以下のフレームから成ります:
一連のフレームの最後のフレームは END_STREAM フラグを持ちます。END_STREAM フラグを持つ HEADERS フレームの後には、残りのヘッダーブロックの一部を転送する CONTINUATION フレームが続くことができることに注意してください。
(任意のストリームの) その他のフレームは、HEADERS フレームとその後に続く可能性のある CONTINUATION フレームの間に存在してはいけません (MUST NOT)。
HTTP/2 はメッセージペイロードの転送に DATA フレームを使用します。[RFC7230] の4.1節で定義されている "chunked" 転送エンコーディングは HTTP/2 では使用してはいけません (MUST NOT)。
Trailing ヘッダーフィールドはストリームを終了するヘッダーブロックにより転送されます。このようなヘッダーブロックは、END_STREAM フラグを持つ HEADERS フレームで始まり、0個以上の CONTINUATION フレームが続く、一連のフレームです。ストリームを終了しない最初のヘッダーブロックの後のヘッダーブロックは HTTP リクエストやレスポンスの一部ではありません。
HEADERS フレーム (とそれに関連付けられた CONTINUATION フレーム) は、ストリームの最初と最後でのみ送信できます。最終的な (Informational でない) ステータスコードを受信した後に、END_STREAM フラグが設定されていない HEADERS フレームを受信したエンドポイントは、対応するリクエストやレスポンスを不正な形式 (8.1.2.6節) として扱わなければなりません (MUST)。
HTTP リクエスト/レスポンスの交換は1つのストリームを完全に消費します。リクエストは、ストリームを "open" 状態にする HEADERS フレームで開始されます。そのリクエストは、ストリームをクライアントでは "half closed (local)" 状態に、サーバーでは "half closed (remote)" 状態にする END_STREAM が設定されたフレームで終了します。レスポンスは HEADERS フレームで開始され、ストリームを "closed" 状態にする END_STREAM が設定されたフレームで終了します。
HTTP レスポンスは、END_STREAM フラグが設定されたフレーム (ヘッダーブロックの完成に必要な CONTINUATION フレームを含む) をサーバーが送信、またはクライアントが受信した時に完了します。レスポンスが未送信または未受信のリクエストの一部に依存しない場合、サーバーは、クライアントがリクエストを完全に送信する前に、完全なレスポンスを送信できます。このような場合、サーバーは、完全なレスポンス (例: END_STREAM フラグが設定されたフレーム) の送信後に NO_ERROR のエラーコードと共に RST_STREAM を送信することで、クライアントにリクエストの送信中止を要求してもよいものとします (MAY)。クライアントは、この他の理由においては常に自身の裁量でレスポンスを破棄できますが、このような RST_STREAM を受信した結果としてのレスポンスは破棄してはいけません (MUST NOT)。
HTTP/2 は 101 (Switching Protocols) 情報提供ステータスコード ([RFC7231]、6.2.2節) の対応を削除します。
101 (Switching Protocols) のセマンティクスは多重化されたプロトコルには適用されません。代替プロトコルは HTTP/2 の使用をネゴシエートするのに使用するものと同じメカニズムを使用できます。
HTTP ヘッダーフィールドは一連のキーと値のペアとして情報を転送します。登録済み HTTP ヘッダーのリストについては、[4] で整備されている メッセージヘッダーフィールドレジストリを参照してください。
HTTP/1.x のようにヘッダーフィールド名は、大文字小文字を区別しない方法で比較される ASCII の文字列です。しかしながら HTTP/2 では、ヘッダーフィールド名はエンコード前に小文字に変換されなければなりません (MUST)。大文字のヘッダーフィールド名を含むリクエストやレスポンスは不正な形式 (8.1.2.6節) として扱わなければなりません (MUST)。
HTTP/1.x では、対象 URI とリクエストのメソッド、そしてレスポンスのステータスコードを転送するためにメッセージ start-line ([RFC7230]、3.1節) を使用していましたが、HTTP/2 では、':' 文字 (ASCII 0x3a) で始まる特殊な擬似ヘッダーフィールドを使用します。
擬似ヘッダーフィールドは HTTP ヘッダーフィールドではありません。エンドポイントはこの文書で定義されたもの以外の擬似ヘッダーフィールドを生成してはいけません (MUST NOT)。
擬似ヘッダーフィールドは、それらが定義されたコンテキストにおいてのみ有効です。リクエストのために定義された擬似ヘッダーフィールドは、レスポンスに使用してはいけません (MUST NOT)。同様に、レスポンスのために定義された擬似ヘッダーフィールドは、リクエストに使用してはいけません (MUST NOT)。擬似ヘッダーフィールドはトレイラーに使用してはいけません (MUST NOT)。エンドポイントは、未定義や無効な擬似ヘッダーフィールドを含むリクエストやレスポンスを不正な形式 (8.1.2.6節) として扱わなければなりません (MUST)。
全ての擬似ヘッダーフィールドは、ヘッダーブロックにおいて通常のヘッダーフィールドよりも前に出現しなければなりません (MUST)。ヘッダーブロックにおいて通常のヘッダーフィールドよりも後に擬似ヘッダーフィールドを含むリクエストやレスポンスは、不正な形式 (8.1.2.6節) として扱わなければなりません (MUST)
HTTP/2 は接続固有ヘッダーフィールドを示す "Connection" ヘッダーフィールドを使用しません。このプロトコルでは、接続固有のメタデータは他の方法で転送されます。エンドポイントは接続固有ヘッダーフィールドを含む HTTP/2 メッセージを生成してはいけません (MUST NOT)。接続固有ヘッダーフィールドを含む全てのメッセージは不正な形式 (8.1.2.6節) として扱われなければなりません (MUST)。
これに関する唯一の例外は、TE ヘッダーフィールドです。このフィールドは HTTP/2 リクエストに存在してもよい (MAY) ものとしていますが、"trailers" 以外の値を含んではいけません (MUST NOT)。
このことは、HTTP/1.x メッセージを HTTP/2 に変換する中継者が、Connection ヘッダーフィールドとそこで指定されたヘッダーフィールドを削除する必要があることを意味します。このような中継者は、Connection で指定されていなくても Keep-Alive、Proxy-Connection、Transfer-Encoding、そして Upgrade といった接続に固有な他のヘッダーフィールドを削除すべきです (SHOULD)。
注: HTTP/2 は他のプロトコルへのアップグレードに意図的に対応しません。3章で説明したハンドシェイク方式は、他のプロトコルの使用をネゴシエートするのに十分と考えられています。
以下の擬似ヘッダーフィールドは HTTP/2 リクエストのために定義されます:
":scheme" 擬似ヘッダーフィールドは、対象 URI のスキーム部 ([RFC3986]、3.1節) を含みます。
":scheme" は "http" と "https" スキームの URI に制限されません。プロキシやゲートウェイは、非 HTTP スキームのリクエストを変換することができ、非 HTTP サービスと通信をするために HTTP の使用を可能にします。
":authority" 擬似ヘッダーフィールドは、対象 URI の authority 部 ([RFC3986]、3.2節) を含みます。authority には、非推奨となった "http" や "https" URI のサブコンポーネントの "userinfo" を含めてはいけません (MUST NOT)。
HTTP/1.1 リクエスト行を正確に再現できることを保証するために、origin や asterisk 形式 ([RFC7230]、5.3節) のリクエストターゲットを持つ HTTP/1.1 リクエストから変換するときには、この擬似ヘッダーフィールドは省略されなければなりません (MUST)。HTTP/2 リクエストを直接生成するクライアントは、"Host" ヘッダーフィールドの代わりに ":authority" 擬似ヘッダーフィールドを使用すべきです (SHOULD)。HTTP/2 リクエストを HTTP/1.1 に変換する中継者は、"Host" ヘッダーフィールドが存在しない場合は、":authority" ヘッダーフィールドの値をコピーして "Host" ヘッダーフィールドを生成しなければなりません (MUST)。
":path" 擬似ヘッダーフィールドは、対象 URI のパス部とクエリー部 ([RFC3986] の "絶対パス" および、クエリーが後に続く任意の '?' 文字、[RFC3986]、3.3節と[RFC3986]、3.4節) を含みます。asterisk 形式のリクエストは ':path' 擬似ヘッダーフィールドに '*' を値として含みます。
この擬似ヘッダーフィールドは、"http" や "https" の URI では空であってはいけません (MUST NOT)。またパスコンポーネントを含まない "http" や "https" の URI では値に '/' を含めなければなりません (MUST)。このルールの例外には、パスコンポーネントを含まない "http" や "https" の URI への OPTIONS リクエストがあります。これらのリクエストは '*' を値に設定 ([RFC7230]、5.3.4節) した ":path" 擬似ヘッダーフィールドを含まなければなりません (MUST)。
全ての HTTP/2 リクエストは、CONNECT リクエスト (8.3節) である場合を除き、":method"、":scheme"、そして ":path" 擬似ヘッダーフィールドに有効な値を1つ含まなければなりません (MUST)。これらの擬似ヘッダーフィールドが省略された HTTP リクエストは不正な形式 (8.1.2.6節) です。
HTTP/2 では、HTTP/1.1 のリクエスト行に含まれるバージョン識別子を伝達する方法を定義しません。
":status" 擬似ヘッダーフィールドは、HTTP/2 レスポンスの HTTP ステータスコードフィールド ([RFC7231]、6節) を伝達するために定義されます。この擬似ヘッダーフィールドは全てのレスポンスに含まれなければなりません (MUST) が、これを含まないレスポンスは不正な形式 (8.1.2.5節) です。
HTTP/2 では、HTTP/1.1 のステータス行に含まれるバージョンや理由フレーズを伝達する方法を定義しません。
Cookie ヘッダーフィールド [COOKIE] はクッキーペア (もしくは "crumb") の区切りにセミコロン ";" を使用します。このヘッダーフィールドは、HTTP におけるリスト構造のルール ([RFC7230]、3.2.2節) には従っていません。そしてそれは、クッキーペアが異なる名前-値ペアに分割されることを妨げています。 このため個々のクッキーペアが更新されると、圧縮効率が著しく低下します。
圧縮効率を向上させるために、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 フレームである一方で、無関係なフレームや禁止されたヘッダーフィールドが存在したり、必須のヘッダーフィールドが存在しない、大文字のヘッダーフィールド名が含まれているなどの理由で無効になるものです。
エンティティボディを持つリクエストやレスポンスは "content-length" ヘッダーフィールドを含むことができます。ボディを構成する DATA フレームペイロードの長さの合計が "content-length" ヘッダーフィールドの値と等しくない場合、リクエストやレスポンスは不正な形式になります。[RFC7230]、3.3.2節で述べられているような、ペイロードを持たないように定義されたレスポンスは、DATA フレームに内容が含まれていない場合であっても、値が0でない "content-length" ヘッダーフィールドを持つことができます。
HTTP のリクエストやレスポンスを処理する中継者 (つまり、トンネルとして機能しない全ての中継者) は、不正な形式のリクエストやレスポンスを転送してはいけません (MUST NOT)。不正な形式のリクエストやレスポンスが検出された場合、PROTOCOL_ERROR のストリームエラー (5.4.2節) として扱わなければなりません (MUST)。
サーバーは不正な形式のリクエストについて、ストリームを終了したり、リセットをする前に HTTP レスポンスを送信してもよいものとします (MAY)。クライアントは不正な形式のレスポンスを受け入れてはいけません (MUST NOT)。これらの要件は、HTTP に対する一般的な攻撃手法の一部からの保護を意図していることに注意してください。寛容であることは、実装の脆弱性を晒すことにもなるため、用心深く、厳格でなければなりません。
この節では、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 :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 リクエストは、リクエストヘッダーフィールドを含む 1つの 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 :path = /resource {binary data} :scheme = https CONTINUATION + END_HEADERS content-type = image/jpeg host = example.org content-length = 123 DATA + END_STREAM {binary data}
任意のヘッダーフィールドを提供するデータは、ヘッダーブロックフラグメントに分割されることに注意してください。この例における、ヘッダーフィールドのフレームへの割り当ては、単純な説明向のものになっています。
ヘッダーフィールドとペイロードデータを含むレスポンスは、1つ以上の 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 フレームとして転送されます。
Trailing ヘッダーフィールドは、リクエストやレスポンスヘッダーブロックと、全ての DATA フレームが送信された後に、ヘッダーブロックとして送信されます。トレイラーヘッダーブロックを開始する HEADERS フレームには END_STREAM フラグが設定されます。
以下の例は、Expect ヘッダーフィールドに "100-continue" トークンを含むリクエストに対するレスポンスとして送信される 100 (Continue) ステータスコードと Trailing ヘッダーフィールドの両方を含む例です。
HTTP/1.1 103 BAR HEADERS Extension-Field: bar ==> - END_STREAM + END_HEADERS :status = 103 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-length = 123 123 content-type = image/jpeg {binary data} trailer = Foo 0 Foo: bar DATA - END_STREAM {binary data} HEADERS + END_STREAM + END_HEADERS foo: bar
HTTP/1.1 においてエラーが発生した際は、エラーの原因を特定する手段が存在しないため、HTTP クライアントは冪等でないリクエストの再試行をおこなうことができませんでした。もしリクエストが再試行されると、エラーが発生する前に進めたサーバー処理が望ましくない結果になってしまう可能性があるでしょう。
HTTP/2 はリクエストが処理されたことをクライアントに保証するために、2つのメカニズムを提供します:
処理されなかったリクエストは失敗ではありません。クライアントはそのリクエストが冪等でないメソッドであっても、それらを自動的に再施行してもよいものとします (MAY)。
ストリームが処理されていないという事をサーバーが保証できない限り、サーバーはそのことを示してはいけません (MUST NOT)。ストリーム上にあるフレームがアプリケーションレイヤーに渡された場合、そのストリームに対して REFUSED_STREAM を使用してはいけません (MUST NOT)。そして GOAWAY フレームは、アプリケーションレイヤーに渡されたフレームのストリームID以上の値を含まなければなりません (MUST)。
これらのメカニズムに加え、PING フレームはクライアントがコネクションを簡単にテストする方法を提供します。いくつかのミドルボックス (例として、ネットワークアドレス変換器やロードバランサーなどがあります) が静かにコネクションを破棄するため、アイドルとして残っているコネクションは破壊されることがあります。PING フレームは、クライアントがリクエストを送信することなく、コネクションが有効かどうかを安全にテストすることを可能にします。
HTTP/2 では、("予約" リクエストへの対応に加えて) クライアントからの先行するリクエストに関連するレスポンスを、サーバーがクライアントに先行送信 (または "プッシュ") することを可能にします。先行するリクエストのレスポンスをクライアントが完全に処理するために、関連するレスポンスを用意する必要があることをサーバーが知っている場合、これは便利です。
この方式における追加のメッセージ交換のプッシュは任意であり、個々のエンドポイントの間でやり取りされます。サーバープッシュが無効であることを示すために、SETTINGS_ENABLE_PUSH 設定には 0 を設定できます。
予約リクエストは、キャッシュ可能 ([RFC7231]、4.2.3節) でなければならず (MUST)、また安全 ([RFC7231]、4.2.1節) でなければなりません (MUST)。また、リクエストボディを含んではいけません (MUST NOT)。キャッシュ可能でない、安全でない、またはリクエストボディを含むような予約リクエストを受信したクライアントは、PROTOCOL_ERROR のストリームエラー (5.4.2節) と共にストリームを初期化しなければなりません (MUST)。
キャッシュ可能 ([RFC7234]、3章) なプッシュレスポンスは、HTTP キャッシュを実装しているクライアントにより保存されます。予約済みストリームIDにより識別されるストリームが open 状態の間、プッシュレスポンスは (例えば "no-cache" キャッシュレスポンスディレクティブ ([RFC7234]、5.2.2節) が存在する場合のように) オリジンサーバーにおいて正常に検証されたとみなされます。
キャッシュ可能でないプッシュレスポンスは HTTP キャッシュにより保存されてはいけません (MUST NOT)。それらは、個々にアプリケーションで利用されてもよいものとします (MAY)。
中間機器はサーバーからのプッシュを受信でき、クライアントへそれらを転送するかを選択できます。言い換えれば、プッシュされる情報をどのように使用するかは中間機器次第です。同様に、中間機器はサーバーによる動作なしに、クライアントへの追加のプッシュを生成する可能性があります。
クライアントはプッシュすることはできません。したがって、サーバーは PUSH_PROMISE フレームの受信を PROTOCOL_ERROR のコネクションエラー (5.4.1節) として扱わなければなりません。クライアントは、PROTOCOL_ERROR のコネクションエラー (5.4.1節) としてメッセージを扱うことで、SETTINGS_ENABLE_PUSH 設定を 0 以外の値に変更しようとする試みを拒否しなければなりません (MUST)。
サーバープッシュは、リクエストに対してサーバーがレスポンスを返すことと意味的に等しくなります。この時のリクエストはサーバーにより PUSH_PROMISE フレームとして送信されます。
PUSH_PROMISE フレームは、サーバーがリクエストに予想するリクエストヘッダーフィールドの完全なセットからなるヘッダーブロックを含みます。リクエストボディを含むリクエストのレスポンスをプッシュすることは不可能です。
プッシュリクエストは、常にクライアントからのリクエストに明確に関連付けられます。サーバーから送信される PUSH_PROMISE フレームは、明示的なリクエストのストリーム上に送信されます。PUSH_PROMSE フレームは予約済みストリームIDも含みます。それはサーバーで使用可能なストリームIDから選択されています (5.1.1節)。
PUSH_PROMISE のヘッダーフィールドと、その後に続く CONTINUATION フレームは、正しく完全なリクエストヘッダーフィールドのセット(8.1.2.3節) でなければなりません (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.1.2.4節) と同じ様にプッシュレスポンスを送信し始めることができます。サーバーは、HTTP レスポンスを送信するためにこのストリームを使用します。それは8.1節で定義された一連のシーケンスを使用しています。このストリームは、初期の HEADERS フレームが送信された後、クライアントに対して "half closed" 状態 (5.1節) に変わります。
クライアントが PUSH_PROMISE フレームを受信し、プッシュレスポンスを受け入れることを選択すると、クライアントは予約済みストリームが終了するまで、そのレスポンスに対してリクエストを発行すべきではありません (SHOULD NOT)。
クライアントが何らかの理由でサーバーからプッシュされたレスポンスの受信を望まないと判断した場合や、サーバーが予約済みレスポンスの送信開始まで時間がかかりすぎる場合には、クライアントは RST_STREAM フレームを送信できます。この RST_STREAM は CANCEL または REFUSED_STREAM コードのいずれかを使用し、予約済みのストリームIDを参照します。
クライアントは、サーバーから同時にプッシュされるレスポンスの数を制限するために SETTINGS_MAX_CONCURRENT_STREAMS 設定を使用できます。値が0に設定された SETTINGS_MAX_CONCURRENT_STREAMS を告知することで、サーバーが必要とするストリームの生成を防ぎ、サーバープッシュを無効にします。これは、サーバーに PUSH_PROMISE の送信を禁止するわけではありません。その場合、クライアントは必要のない予約済みのストリームをリセットする必要があります。
プッシュレスポンスを受信するクライアントは、サーバーが信頼できるか (10.1節)、プッシュレスポンスを提供したプロキシが対応するリクエストを設定したかを検証しなければなりません (MUST)。例えば、DNS-ID や Common Name が "example.com" の証明書を提供するサーバーが、"https://www.example.org/doc" のレスポンスをプッシュすることは認められていません。
PUSH_PROMISE レスポンスのストリームは HEADERS フレームと共に始まり、直ちにそのストリームをサーバー上では "half closed (remote)" 状態に、クライアント上では "half closed (local)" 状態にします。そして、ストリームを "closed" 状態にする END_STREAM が設定したフレームにより終了します。
注: クライアントはサーバープッシュに対して END_STREAM フラグを設定したフレームを送信してはいけません。
HTTP/1.x において、擬似メソッド CONNECT ([RFC7231]、4.3.6節) は HTTP 接続をリモートホストへのトンネルに変換するために使用されます。CONNECT は、"https" リソースをやりとりする目的でオリジンサーバーと TLS セッションを確立するために、主に HTTP プロキシと共に使用されます。
HTTP/2 における CONNECT メソッドは、同様にリモートホストへの単一の HTTP/2 ストリーム上にトンネルを確立するために使用されます。HTTP ヘッダーフィールドのマッピングは、リクエストヘッダーフィールド (8.1.2.3節) に定義されたように動作します。一部のヘッダーについては、具体的には以下のようになります。
これらの制限に適合しない CONNECT リクエストは、不正な形式 (8.1.2.6) になります。
CONNECT に対応するプロキシは、":authority" ヘッダーフィールドに指定されたサーバーと TCP コネクション [TCP] を確立します。コネクションの確立に成功すると、[RFC7231]、4.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 プロトコルの属性や、既知のセキュリティ脆弱性に対象する方法、実装差異が起こる可能性を減らす方法などについて説明します。
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.3節) を使用して作成されたトンネルを通じての接続かに関わらず、複数の異なる authority コンポーネントの URI に対するリクエストの送信に再利用されてもよいものとします (MAY)。コネクションはオリジンサーバーが信頼できる (10.1節) 限り、再利用できます。"http" リソースでは、これは同一のIPアドレスとして解決されるホストに依存します。
"https" リソースでのコネクションの再利用は、さらに URI におけるホストに対する有効な証明書を持つかに依存します。オリジンサーバーは、URI の authority に対して有効となる複数の "subjectAltName" 属性や、ワイルドカードの名前と共に証明書を提示するかもしれません。例えば、"subjectAltName" が "*.example.com" の証明書は、"https://a.example.com/" や "https://b.example.com/" で始まる URI へのリクエストに同じコネクションの使用を認めるかもしれません。
一部のデプロイにおいては、複数のオリジンに対するコネクションの再利用が、誤ったオリジンサーバーへのリクエストの送信につながる可能性があります。例えば TLS の終端が、オリジンサーバーの選択に TLS Server Name Indication (SNI) [TLS-EXT] を使用するミドルボックスによっておこなわれている可能性があります。これは、信頼できないサーバーであるにも関わらず、リクエスト対象として意図していないサーバーに対して、クライアントが機密情報を送信してしまう可能性があることを意味します。
クライアントにおけるコネクションの再利用を望まないサーバーは、リクエストに対して 421 (Misdirected Request) をレスポンスとして返すことで、リクエストの権限がないことを示すことができます。
HTTP/2 のプロキシを使用するように設定されたクライアントは、単一のコネクションを通じてそのプロキシにリクエストを送信します。つまり、プロキシ経由で送信されたすべてのリクエストは、プロキシへの接続を再利用します。
421 (Misdirected Request) ステータスコードは、レスポンスを生成できないサーバーにリクエストを送信したことを示します。これは、リクエスト URI に含まれる scheme と authority の組み合わせに対するレスポンスを生成するように設定されていないサーバーから送信される可能性があります。
サーバーから 421 (Misdirected Request) レスポンスを受信したクライアントは、リクエストメソッドが冪等であるかどうかに関わらず、異なるコネクションを通じてリクエストを再施行してもよいものとします (MAY)。これは、コネクションが再利用 (9.1.1節) されていたり、代替サービス ([ALT-SVC])が選択されていたりする場合でも可能です。
このステータスコードは、プロキシから生成されてはいけません (MUST NOT)。
明示的なキャッシュ制御 ([RFC7234]、4.2.2節)や、メソッドの定義により示されない限り、421 レスポンスはデフォルトでキャッシュ可能です。
HTTP/2 の実装は、TLS 上の HTTP/2 に対して TLS [TLS12] のバージョン1.2以上を使用しなければなりません (MUST)。[TLSBCP] にある TLS の一般的な利用ガイダンスに即すべきであり (SHOULD)、加えて HTTP/2 特有の制限もあります。
TLS の実装は、TLS の Server Name Indication (SNI) [TLS-EXT] 拡張に対応しなければなりません (MUST)。HTTP/2 クライアントは、TLS ネゴシエーションの際に対象のドメイン名を指示しなければなりません (MUST)。
TLS 1.3 以上でネゴシエートする HTTP/2 のデプロイメントに求められるのは、SNI 拡張のサポートとその使用のみです。TLS 1.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節) を使用するかもしれません。
実装は、一時的な Diffie-Hellman (DHE) [TLS12] の暗号スイートに対しては最低でも2048ビット、一時的な楕円暗号 (ECDHE) [RFC4492] の暗号スイートに対しては最低でも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 1.2 を使う HTTP/2 の実装は、楕円曲線 P256 [FIPS186] を使用した TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 [TLS-ECDHE] に対応しなければなりません (MUST)。
クライアントは、HTTP/2 をサポートしない、または禁止された暗号スイートのみをサポートするサーバーへの接続を可能にするために、上述の制約により制限された暗号スイートのサポートを通知する可能性があることに注意してください。これにより、サーバーは HTTP/2 で禁止された暗号スイートと共に HTTP/1.1 を選択できます。しかしながら、これはアプリケーションプロトコルと暗号スイートが独立して選択された場合に、禁止された暗号スイートと共に HTTP/2 がネゴシエートされる結果を生みます。
HTTP/2 は、サーバーが対象のリソースの提供する権限があるかどうかを判定するために HTTP/1.1 の権限の定義に依存しています。[RFC7230]、9.1節を参照してください。"http" URI スキームではローカル名前解決、"https" スキームでは信頼されたサーバー識別子 ([RFC2818]、3章) にそれぞれ依存します。
クロスプロトコル攻撃では、攻撃者は異なるプロトコルを解釈するサーバーに対して、クライアントに最初のプロトコルでトランザクションを開始させます。これにより、攻撃者は第二のプロトコルの有効なトランザクションのように見えるトランザクションを開始できるかもしれません。Web コンテキストの機能と組み合わせることで、これはプライベートネットワーク内の不十分な保護下にあるサーバーと通信をするために使用できます。
HTTP/2 の ALPN 識別子と共に TLS ハンドシェイクを完了することは、クロスプロトコル攻撃に対して十分な保護になると考えられます。ALPN は他の TLS ベースのプロトコルへの攻撃を防ぎ、サーバーが HTTP/2 を処理するための前向きな意思表示を提供します。
TLS の暗号化は、攻撃者が平文プロトコル上でクロスプロトコル攻撃に使用するようなデータの制御を難しくします。
平文バージョンの HTTP/2 はクロスプロトコル攻撃に対する最低限の保護しか持ちません。コネクションプリフェイス (3.5節) は HTTP/1.1 サーバーを混乱させるように設計された文字列を含みますが、他のプロトコルに対する特別な保護を提供しません。クライアントコネクションプリフェイスに加えて、Upgrade ヘッダーフィールドを含む HTTP/1.1 リクエストの一部を無視する意思のあるサーバーは、クロスプロトコル攻撃にさらされる可能性があります。
HTTP/2 のヘッダーフィールドエンコードでは、HTTP/1.1 で使用されるインターネットメッセージ構文においては有効でないフィールド名の使用が可能です。不正なヘッダーフィールド名を含むリクエストやレスポンスは不正な形式 (8.1.2.6節) として扱われなければなりません (MUST)。したがって、中継者は不正なフィールド名を含む HTTP/2 リクエストやレスポンスを HTTP/1.1 メッセージに変換できません。
同様に、HTTP/2 は有効でないヘッダーフィールドの値も使用可能です。エンコード可能なほとんどの値では、ヘッダーフィールドの解析を変更しませんが、キャリッジリターン (CR, ASCII 0xd)、ラインフィード (LF, ASCII 0xa)、ヌル文字 (NUL, ASCII 0x0) は、逐語的に変換される場合に攻撃者により悪用される場合があります。ヘッダーフィールドの値に許可されていない文字を含むリクエストやレスポンスは、不正な形式 (8.1.2.6節) として扱われなければなりません (MUST)。有効な文字は [RFC7230]、3.2節の "field-content" ABNF ルールに定義されています。
プッシュレスポンスとはクライアントからの明確なリクエストがないレスポンスです。リクエストは PUSH_PROMISE フレームによりサーバーから提供されます。
プッシュされたレスポンスのキャッシュは可能です。これはオリジンサーバーの Cache-Control ヘッダーフィールドが提供する指示に基づいておこなわれます。しかしながら、1つのサーバーホストが複数のテナントを提供する場合は、問題を引き起こす可能性があります。例えば、サーバーは複数のユーザーにそれぞれ URI 空間の一部を提供するかもしれません。
複数のテナントが同一サーバーの空間を共有する場合、サーバーは、テナントがリソースの権限を超えてキャッシュをプッシュしないことを保証しなければなりません (MUST)。これを強制しなければ、権限のあるテナントが提供する実際のキャッシュを上書きし、本来のキャッシュの外で提供されたキャッシュを、サーバーが提供することが可能になってしまいます。
権限のないオリジンサーバー (10.1節) のプッシュレスポンスを、使用したりキャッシュすることはありません。
HTTP/2 接続は、HTTP/1.1 接続よりも機能のためにより大きなリソースの割り当てを要求します。ヘッダー圧縮およびフロー制御の使用はより多くの状態を保持するため、リソースの割り当てに依存します。これらの機能の設定は、各機能に対するメモリーの割り当てを厳密に制限することを保証します。
PUSH_PROMISE フレームの数は、同様の方法では制限できません。サーバープッシュを受け入れるクライアントは、"reserved (remote)" 状態にできるストリームの数を制限すべきです (SHOULD)。極端な数のサーバープッシュストリームは、ENHANCE_YOUR_CALM のストリームエラー (5.4.2節) として扱うことができます。
処理能力については、状態容量ほどより効果的に保護することはできません。
SETTINGS フレームは、ピアに追加の処理時間を発生させるために悪用される可能性があります。これは、無意味な SETTINGS パラメーターの変更や複数の未定義のパラメーターの変更、同一フレームにおいて同じ設定を複数回変更をするなどで起こる可能性があります。同様に、WINDOW_UPDATE や PRIORITY フレームも、無駄なリソースの消費を引き起こすために悪用される可能性があります。
小さな、または空の大量のフレームは、ピアにフレームヘッダーの処理時間を消費させるために悪用される可能性があります。用途によっては、ストリームを終了させるために空の DATA フレームを送信するといった、正しい方法でも使われることに注意してください。
ヘッダー圧縮も、処理リソースを浪費するいくつかの機会を提供します。悪用の可能性についての詳細は [COMPRESSION] の7章を参照してください。
SETTINGS パラメーターの制限では、直ちに処理を軽減させることはできません。エンドポイントは、ピアが新しく設定しようとした制限値を超えられる状況に晒されたままです。特にコネクションが確立した直後は、サーバーによって設定される制限値がクライアントに通知されておらず、その場合明らかにプロトコル違反にならずに制限値を超えることが可能です。
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)。
HTTP/2 はヘッダーフィールド (4.3節) とエンティティボディの両方の圧縮のより多く利用します。圧縮は、攻撃者の制御下でかつ同じコンテキストで圧縮された場合に、攻撃者による機密データの復元を可能にします。
Web の特性を利用した圧縮に関する攻撃手法 (例: [BREACH]) もあります。攻撃者は様々な平文を含む複数のリクエストを誘発し、得られた各暗号テキストの長さを観測します。推測した機密が正しければ、その長さは短くなります。
保護されたチャンネル上で通信する実装は、各データソースに異なる圧縮辞書を使わない限り、機密と攻撃者が制御するデータの両方を含む内容を圧縮してはいけません (MUST NOT)。データソースが確実に判断できない場合は、圧縮を使用してはいけません (MUST NOT)。TLS で提供されているような汎用的なストリーム圧縮は HTTP/2 で使用してはいけません (MUST NOT) (9.2節)。
HTTP/2 におけるパディングは、TLS [TLS12] により提供されるような一般的なパディングの置き換えを意図していません。冗長なパディングは逆効果にもなり得ます。正しいアプリケーションであるかどうかは、パディングされたデータに関する特別な情報を持つことによって決まります。
圧縮を利用した攻撃を軽減するための圧縮機能の無効化や制限は、対抗策としてのパディングよりも適しているかもしれません。
パッディングはフレームの内容の正確なサイズをわかりにくくするために使用でき、HTTP の特定の攻撃を軽減するために提供されます。例えば、攻撃者により制御されたプレーンテキストと機密データを含む圧縮コンテンツにおける攻撃 ([BREACH] の例を参照してください) があります。
パディングの使用は、一見してわかる防御よりも結果的に弱い防御に終わることがあります。パディングは攻撃者が観察しなければならないフレームの数を増加させることで、長さ情報の推測をより困難にすることしかできません。不適切に実装されたパディングの構造は、簡単に破られる可能性があります。特に予測可能な分布によるランダムなパッディングは、非常にわずかな保護しか提供できません。同様に、パディングペイロードを固定サイズにすることは、ペイロードサイズをその固定サイズの境界を超えるように変更することで、情報を漏洩させます。これは攻撃者がプレーンテキストの制御が可能な場合に起こりえます。
中継者は DATA フレームのパディングを維持すべきです (SHOUD)。しかしながら、HEADERS や PUSH_PROMISE フレームのパディングは削除してもよいものとします (MAY)。中継者がフレームのパディングの量を変更する正当な理由は、パディングが提供する保護を改善することにあります。
HTTP/2 のいくつかの特徴は、時間をかけてサーバーやクライアントの関連する動作を観測する機会を提供します。これには、設定の値やフロー制御ウインドウの管理方法、優先度がストリームに割り当てられる方法、攻撃に対する反応のタイミング、任意の機能の扱いなどを含みます。
観測可能な振る舞いの違いを生み出す限り、[HTML5] の1.8節で定義されているように、特定クライアントのフィンガープリントの取得に使用することができてしまいます。
HTTP/2 が単一の TCP 接続を使用することで、サイト上でのユーザーの行動を相関させることが可能になります。コネクションが異なるオリジンに再利用された場合は、それらのオリジンを超えて追跡の追跡が可能になります。
PING や SETTINGS フレームへの応答が直ちに求められるのは、これらのフレームがエンドポイントからピアへのレイテンシの計測に使用されるためです。これは、特定のシナリオでプライバシーへの影響があるかもしれません。
HTTP/2 を識別するための文字列は、[TLS-ALPN] に記載される "Application Layer Protocol Negotiation (ALPN) Protocol IDs" レジストリに登録されます。
この文書では、フレームタイプ、設定、そしてエラーコードのレジストリを制定します。これらの新しいレジストリは、新しい "Hypertext Transfer Protocol (HTTP) 2 Parameters" の章に追加されます。
この文書では HTTP で使用する "HTTP2-Settings" ヘッダーフィールドと、421 (Misdirected Request) ステータスコードを登録します。
この文書では、コネクションプリフェイス (3.5節) との衝突を防ぐために HTTP で使用する "PRI" メソッドを登録します。
この文書は [TLS-ALPN] に記載される "Application Layer Protocol Negotiation (ALPN) Protocol IDs" レジストリにおける HTTP/2 識別子の登録について制定します。
文字列 "h2" は TLS 上で使用される HTTP/2 を識別します。
文字列 "h2c" は平文 TCP 上で使用される HTTP/2 を識別します。
この文書は HTTP/2 フレームタイプコードのレジストリを制定します。"HTTP/2 Frame Type" レジストリは8ビットの空間を管理します。"HTTP/2 Frame Type" レジストリは "IETF Review" や "IESG Approval" ポリシー [RFC5226] の下で、0x00 から 0xef までの値の範囲で運用されます。なお、0xf0 から 0xff までの値は実験的な利用のために予約されます。
このレジストリの新しいエントリーには、以下の情報が要求されます。
以下のテーブルのエントリはこの文書で登録されます。
+---------------+------+--------------+ | Frame Type | Code | Section | +---------------+------+--------------+ | DATA | 0x0 | Section 6.1 | | HEADERS | 0x1 | Section 6.2 | | PRIORITY | 0x2 | Section 6.3 | | RST_STREAM | 0x3 | Section 6.4 | | SETTINGS | 0x4 | Section 6.5 | | PUSH_PROMISE | 0x5 | Section 6.6 | | PING | 0x6 | Section 6.7 | | GOAWAY | 0x7 | Section 6.8 | | WINDOW_UPDATE | 0x8 | Section 6.9 | | CONTINUATION | 0x9 | Section 6.10 | +---------------+------+--------------+
この文書は HTTP/2 設定のレジストリを制定します。"HTTP/2 Settings" レジストリは16ビットの空間を管理します。"HTTP/2 Settings" レジストリは "Expert Review" ポリシー [RFC5226] の下で、0x0000 から 0xefff までの値の範囲で運用されます。なお、0xf000 から 0xffff までの値は実験的な利用のために予約されます。
新しい登録には、以下の情報を提供することが推奨されます。
登録設定の初期セットは、6.5.2節に記載されています。
+------------------------+------+---------------+---------------+ | Name | Code | Initial Value | Specification | +------------------------+------+---------------+---------------+ | HEADER_TABLE_SIZE | 0x1 | 4096 | Section 6.5.2 | | ENABLE_PUSH | 0x2 | 1 | Section 6.5.2 | | MAX_CONCURRENT_STREAMS | 0x3 | (infinite) | Section 6.5.2 | | INITIAL_WINDOW_SIZE | 0x4 | 65535 | Section 6.5.2 | | MAX_FRAME_SIZE | 0x5 | 16384 | Section 6.5.2 | | MAX_HEADER_LIST_SIZE | 0x6 | (infinite) | Section 6.5.2 | +------------------------+------+---------------+---------------+
この文書は HTTP/2 エラーコードのレジストリを制定します。"HTTP/2 Error Code" レジストリは32ビットの空間を管理します。 "HTTP/2 Error Code" レジストリは、"Expert Review" ポリシー [RFC5226] に従って運用します。
エラーコードの登録には、そのエラーコードの説明を含める必要があります。専門のレビュアーは新規の登録が既存のエラーコードと重複可能かについて検討することを推奨します。既存の登録の使用は推奨されますが、義務ではありません。
新しい登録は以下の情報の提供が推奨されます。
以下のテーブルのエントリはこの文書で登録されます。
+---------------------+------+----------------------+---------------+ | Name | Code | Description | Specification | +---------------------+------+----------------------+---------------+ | NO_ERROR | 0x0 | Graceful shutdown | Section 7 | | PROTOCOL_ERROR | 0x1 | Protocol error | Section 7 | | | | detected | | | INTERNAL_ERROR | 0x2 | Implementation fault | Section 7 | | FLOW_CONTROL_ERROR | 0x3 | Flow control limits | Section 7 | | | | exceeded | | | SETTINGS_TIMEOUT | 0x4 | Settings not | Section 7 | | | | acknowledged | | | STREAM_CLOSED | 0x5 | Frame received for | Section 7 | | | | closed stream | | | FRAME_SIZE_ERROR | 0x6 | Frame size incorrect | Section 7 | | REFUSED_STREAM | 0x7 | Stream not processed | Section 7 | | CANCEL | 0x8 | Stream cancelled | Section 7 | | COMPRESSION_ERROR | 0x9 | Compression state | Section 7 | | | | not updated | | | CONNECT_ERROR | 0xa | TCP connection error | Section 7 | | | | for CONNECT method | | | ENHANCE_YOUR_CALM | 0xb | Processing capacity | Section 7 | | | | exceeded | | | INADEQUATE_SECURITY | 0xc | Negotiated TLS | Section 7 | | | | parameters not | | | | | acceptable | | | HTTP_1_1_REQUIRED | 0xd | Use HTTP/1.1 for the | Section 7 | | | | request | | +---------------------+------+----------------------+---------------+
この節は、"HTTP2-Settings" ヘッダーフィールドを Permanent Message Header Field Registry [BCP90] に登録します。
この節は、"PRI" メソッドを HTTP Method Registry ([RFC7231]、8.1節) に登録します。
この文書は 421 (Misdirected Request) HTTP ステータスコードを Hypertext Transfer Protocol (HTTP) Status Code Registry ([RFC7231]、8.2節) に登録します。
この文書は、以下の個人からの多くの意見を含んでいます:
以下の暗号スイートは、TLS 1.2 上の HTTP/2 での使用が禁止されます:
注: このリストは、執筆時に登録されている TLS 暗号スイートのセットから構成されています。このリストには、一時鍵の交換を提供しない暗号スイートや、TLS null、ストリームまたはブロック暗号 ([TLS12]、6.2.3節で定義) に分類される種類の暗号スイートを含んでいます。これらと同様の性質を持つ追加の暗号スイートは定義可能ですが、それらは明示的に禁止されません。
この章は公開前に RFC 編集者により削除されます。