ストリーム

ストリーム (HTTP)

[2] ストリーム (stream) は、HTTP/2接続中の独立したフレーム双方向の流れ (bidirectional flow) (列) です >>1, >>3。 一組の要求応答を送受信するために使います。 ストリームHTTP/2 で新たに導入された概念です。

[136] 一つの接続内で複数のストリームを使うことにより、 複数の要求並行して処理できます。

仕様書

プロトコル

[4] HTTP/2接続は、並行して複数のフレームを開くことができます。 つまり複数のストリームフレームを混在させて送受信できます。 >>3

[5] ストリームは、サーバークライアントのどちらからも確立したり閉じたりできますし、 一方だけで使ったり、両方で使ったりできます。 >>3

[7] HTTP/2接続の開始の時点では、ストリームはありません。

[86] ただし理論上は HTTP/1.1 から Upgrade: h2cHTTP/2 で切り替えた場合は、ストリーム識別子 0x1 が使われた状態となります。

HTTP/2接続参照。

[65] エンドポイントは、各ストリームの次の情報を保持します。

ストリーム識別子 >>3
符号無し31ビット整数
開始した peer
ストリーム識別子奇数ならクライアント偶数ならサーバーです >>3
状態
状態遷移図上の状態のいずれかです (>>8)。 closed 状態には付随していくつかのフラグがあります。
親ストリーム
依存性木上のです。必ず1つ存在します。 依存ストリームの逆方向の関係です。
依存ストリーム
依存性木上の集合です。 0個以上ストリームが含まれます。
重み
親ストリームから本ストリームへの依存性木上のに割り当てられた、 優先度を表す値です。
処理開始済み
データをアプリケーション層に伝えたかどうかを表すフラグです。 GOAWAY フレーム送信時に使います。
RST_STREAM タイムスタンプ
RST_STREAM フレーム再送判定に使います。
ストリームフロー制御窓

[6] ストリームにおけるフレームの順序には意味があり、 受信者は受信した順序で処理する必要があります。 >>3

状態

[8] エンドポイントは、ストリーム状態 (state) を保持します。 >>3

[9] ストリームの状態は、エンドポイントがそれぞれ保持しているもので、 フレームの転送中は peer と異なることがあります。 >>3 また (local) と (remote) のような対となる状態になっていることもあります。

[50] 状態は、フレームの送受信で遷移します。単一のフレームで複数の状態遷移が発生することもあります。

[63] 未知のフレーム型フレームは無視して捨てなければなりません >>3, >>75。しかし後述の通り、 指定されたフレームの種類以外はエラーとなるとの規定もあります。 どちらの規定が優先されるのかは不明ですが、この両文が RFC では隣に並んでいるので、無視が優先されるとエスパーできます。

[76] 捨てられるフレームも、他の要件には影響することがあります。 ヘッダーリストフレームを参照。

[144] GOAWAY フレームを受信したら、 その最終ストリーム識別子よりも大きなストリームについて RST_STREAM フレームを受信したものとして処理するべきと思われます。

[66] 次の状態があります。

idle
idle
v
>>
1
->
reserved.local
->
reserved.remote
->
open
->
closed
reserved.local
reserved (local)
->
half.remote
->
closed
reserved.remote
reserved (remote)
>>
4
->
half.local
->
closed
open
open
v
>>
1
->
half.local
->
half.remote
->
closed
half.remote
half-closed (remote)
v
->
closed
half.local
half-closed (local)
>>
4
->
closed
closed
closed
v
>>
2

[89] 状態毎に、送信できるフレーム型の制約があります。

状態DATAHEADERSPRIORITYRST_STREAMSETTINGSPUSH_PROMISEPINGGOAWAYWINDOW_UPDATECONTINUATIONその他
idle×××××××××
reserved (local)××××××××
reserved (remote)××××××××
open××××
half-closed (local)×××××××
half-closed (remote)××××
closed×××××××××
接続×××××××

各状態においても更に細かい制約があるかもしれません。

idle

[10] ストリームは、作成されると idle 状態となります >>3

[11] エンドポイントは、peer と協調せずとも自身でストリームを作成できます >>3。相手に伝わるまでは、一方のみにストリームが存在する状態となります。

[22] 送信できるフレームの種類の制約は明記されていませんが、 HEADERSPRIORITY しか送信できないと見られます。

[12] 送受信するフレームの種類により、次のような状態遷移があります >>3

[16] HEADERSPRIORITY 以外のフレームを受信したら、 接続エラー PROTOCOL_ERROR としなければなりません >>3

[137] RST_STREAMWINDOW_UPDATE接続エラーとなるようです。

[139] 実際には WINDOW_UPDATE を受信したら Firefoxストリームエラー PROTOCOL_ERROR とし、 Chrome は無視するようです。

[142] FirefoxChromeRST_STREAM を受信してもエラーとはしないようです。 (closed に遷移しているものと思われます。)

reserved (local)

[17] PUSH_PROMISE フレームで約束すると、 ストリームreserved (local) 状態となります >>3

[23] HEADERS, RST_STREAM, PRIORITY 以外を送信してはなりません >>3

[19] 送受信するフレームの種類により、次のような状態遷移があります >>3

[24] RST_STREAM, PRIORITY, WINDOW_UPDATE 以外のフレームを受信したら、 接続エラー PROTOCOL_ERROR としなければなりません >>3

reserved (remote)

[25] reserved (remote) 状態は、ストリームpeer により予約されていることを表します >>3

[29] RST_STREAM, WINDOW_UPDATE, PRIORITY 以外を送信してはなりません >>3

[26] 送受信するフレームの種類により、次のような状態遷移があります >>3

[30] HEADERS, RST_STREAM, PRIORITY 以外のフレームを受信したら、 接続エラー PROTOCOL_ERROR としなければなりません >>3

open

[31] open 状態では、任意のフレームの送受信ができます。

[34] 送信できるフレームの種類の制約はありません >>3

[32] 本状態に遷移することになったフレームの種類や本状態で送受信するフレームの種類により、次のような状態遷移があります >>3

half-closed (local)

[37] half-closed (local) 状態では、メッセージを送信できませんが、受信するかもしれません。

[38] WINDOW_UPDATE, PRIORITY, RST_STREAM 以外のフレームを送信することはできません >>3

[42] こちらは閉じた (送信しない) 状態ですが、 peer はまだ送信できる状態ですから、 データを受信する準備は継続しなければなりません。 すなわち、 WINDOW_UPDATE フレームを適宜送信する必要があります >>3
[122] 本状態へ遷移させた END_STREAM フラグ付き HEADERS フレームの続きの CONTINUATION フレームを送信することはできます。

[39] 本状態で送受信するフレームの種類により、次のような状態遷移があります >>3

half-closed (remote)

[43] half-closed (remote) 状態は、 peerフレームの送信をもう行わないストリームを表します >>3

[46] 任意のフレームを送信できます >>3

[44] この状態になると、受信者フロー制御窓を維持する義務はありません >>3

[47] 本状態で送受信するフレームの種類により、次のような状態遷移があります >>3

[45] WINDOW_UPDATE >>3, >>134, RST_STREAM, PRIORITY 以外のフレームを受信したら、 ストリームエラー STREAM_CLOSED としなければなりません >>3

[120] ただし、本状態に遷移させた HEADERS フレームに引き続き CONTINUATION フレームを受信する場合は除きます。

closed

[51] closed 状態は、最終的な状態です >>3

[93] この状態での動作は、次の各フラグによって変わります。

[96] この状態に遷移したら、次のようにします。

  1. [90] RST_STREAM フレームを自身が送信したことにより遷移した場合は、「RST_STREAM 送信」タイムスタンプを現在時刻に設定します。
  2. [91] END_STREAM フラグが設定されたフレームを自身が送信したことにより遷移した場合は、「END_STREAM 送信」タイムスタンプを現在時刻に設定します。
  3. [97] RST_STREAM フレームを受信したことにより遷移した場合は、 「RST_STREAM 受信済み」フラグを設定します。
  4. [104] END_STREAM フラグが設定されたフレームを受信したことにより遷移した場合は、 「END_STREAM 受信済み」フラグを設定します。

[99] この状態でフレームを受信したら、次のようにします。

  1. [106]END_STREAM 受信済み」フラグが設定されていれば、
    1. [54] 接続エラー STREAM_CLOSED としなければなりません >>3。 停止します。
  2. [102]RST_STREAM 受信済み」フラグが設定されていれば、
    1. [103] PRIORITY 以外のフレームなら、
      1. [53] ストリームエラー STREAM_CLOSED としなければなりません >>3。停止します。
  3. [100] RST_STREAM フレームなら、
    1. [101]RST_STREAM 受信済み」フラグを設定します。
  4. [107] DATA フレームHEADERS フレームなら、
    1. [108] END_STREAM フラグが設定されていれば、
      1. [109]END_STREAM 受信済み」フラグを設定します。
  5. [112]END_STREAM 送信」タイムスタンプが設定されていれば、
    1. [114] WINDOW_UPDATE フレーム >>3, >>134RST_STREAM フレームなら、
      1. [92] 十分な時間が経過していれば、 接続エラー PROTOCOL_ERROR としても構いません >>3
      2. [113] そうでなければ、無視しなければなりません >>3。停止します。
  6. [57]RST_STREAM 送信」タイムスタンプが設定されている場合、
    1. [115] 十分な時間が経過していれば、
      1. [116] エラーとしても構いません >>3接続エラー PROTOCOL_ERROR が適切そうです。停止します。
    2. [58] 1RTT を過ぎているなら、
      1. [72] 改めて RST_STREAM フレームを送信しても構いません >>71
    3. [59] フロー制御対象のフレーム (DATA) なら、
      1. [119] 接続フロー制御窓の計算に含めます。 >>3 (フレームが無視されるとしても、相手が RST_STREAM を受信する前にフロー制御窓で数えてから送信しているはずだからです。 >>3)
    4. [61] PUSH_PROMISE フレームなら、
      1. [60] 指定されたストリームreserved (remote) 状態とします。 (そちらのストリームは不要なら別途 RST_STREAM が必要です。) >>3
    5. [55] 無視しなければなりません >>3 。停止します。
  7. [110] PRIORITY フレームなら、
    1. [124] 依存性木からストリームが削除済みなら、無視します >>3
    2. [111] 処理するべきです >>3
  8. [117] それ以外なら、
    1. [118] 接続エラー PROTOCOL_ERROR とするべきです >>3

[138] ChromeFirefox も、 STREAM_CLOSED は送信せずに無視するだけのように見えます。

[52] PRIORITY フレーム以外を送信してはなりません >>3

[123] 本状態へ遷移させた END_STREAM フラグ付き HEADERS フレームの続きの CONTINUATION フレームを送受信することはできます。
[18] RST_STREAM フレームの送信によって closed に遷移すると、 peer との状態遷移の時間差が原因で、 この状態となった後にフレームを受信する可能性もあります >>3peer が既に送信したり、 送信準備をしたりして、取り消せなかったフレームが到着する場合があります >>3RST_STREAM フレーム送信後もフレームを受信する準備をしておかなければなりません >>71
[56] 自身が END_STREAMRST_STREAM を送信してから相手が受信するまでの時間差があるため、その間に WINDOW_UPDATERST_STREAM を受信する可能性があります。 >>3
[62] RFCclosed を1つの状態として表していますが、 実際には何により遷移してきたかで処理を分ける必要があり、また時間経過などで処理が変わる可能性があり、 複雑です。しかも RFC は「無視する (無視するとは言っていない)」のような変な書き方になっていて難解です。 >>99RFC の規定を出来る限り矛盾せずに整理した結果ですが、 これ以外の解釈もあり得るかもしれません。

[73] (>>58 を除き) RST_STREAM フレームを複数送信するべきではありません >>71

[140] FirefoxHEADERS を受信する前に RST_STREAM を受信したら接続エラー PROTOCOL_ERROR とします。 Chrome はそれ自体はエラーとせずに無視しますが、その直後に HEADERS を受信したらストリームエラー PROTOCOL_ERROR とします。

[141] FirefoxChromeEND_STREAM 後の RST_STREAM は無視するようです。相当する要求に対する応答も、 ネットワークエラーとはなりません。

[125] closed 状態のストリームは、一定時間後、依存性木から削除できます。

依存性木を参照。

並行性

[67] 設定 SETTINGS_MAX_CONCURRENT_STREAMS (0x3) は、送信者が認める並行ストリームの最大数を表します >>77, >>3

[79] 初期状態は無制限です >>77

[78] 不必要に並列性を損なわないため、 この値を 100 未満とするべきではありません (recommend) >>77

[80] 値0は、特別な意味は持ちません。新しいストリームの生成が認められないことを表します。 しかしサーバーは短い時間に限ってのみ 0 を使うべきです要求を受け付けたくない時は、接続を閉じる方が適切です。 >>77

[68] この設定は、受信者が開始することを認められたストリームの数を示しています。 従ってクライアントサーバーの開始するストリームの最大数を指定でき、 サーバークライアントの開始するストリームの最大数を指定できます。 >>3, >>77

[81] ここで数に含まれるのは、 open, half-closed (local), half-closed (remote) のいずれかの状態にあるストリームです >>3

[69] HEADERS フレームを受信した時、 ストリーム数上限を超えるなら、 PROTOCOL_ERROR または REFUSED_STREAMストリームエラーとしなければなりません。 どちらを選ぶかは、自動的な再試行を有効にしたいかに依ります。 >>3

[70] SETTINGS_MAX_CONCURRENT_STREAMS の値が現在のストリームの数よりも小さくなる場合は、 新しい値を超えたストリームを閉じることもできますし、 ストリームが完了するまで待つこともできます。 >>3

[84] Chrome接続序文で 1000 を値として設定します。

接続の切断

[74] HTTP/2接続を参照。

[131] GOAWAY フレームを受信したら、以後新しいストリームを作成してはなりません >>130

[132] しかし既存のストリームの送受信処理は、継続できます。

[133] GOAWAY フレームの送信後であっても、 受信して処理を継続しなければなりません。無視するストリームフレームも、 ヘッダーブロックフロー制御の処理は行わなければなりません >>130

END_STREAM フラグ

[127] DATA フレームHEADERS フレームEND_STREAM (0x1 = 第0ビット) フラグは、設定されていれば当該ストリームの当該送信者からの最後のフレームであることを表します。 >>126, >>128

[129] 実際には CONTINUATION フレームも直後に送信されるかもしれません >>128

[121] END_STREAM フラグが設定されたフレームを送受信すると、 closed 状態に遷移します >>3。本フラグの送受信が他のフレームの処理にも影響します。

状態遷移の項を参照。

[135] CONNECT では、 TCP FIN フラグに相当します >>85

誤り符号 STREAM_CLOSED

[83] STREAM_CLOSED (0x5) は、 ストリームhalf-closed の後にフレームを受信したことを示します >>82