HTTP2のストリーム状態遷移

後追いながら、HTTP2の勉強をしてます。

少しずつ理解できてきたような気がする。
間違っていたら詳しい方はご指摘ください。

# ストリーム状態遷移

ストリームには状態があり、送信できるフレームと送信できないフレームがある。

http://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-5.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  |
`---------------------->|        |<----------------------'
                        +--------+

  H:  HEADERS フレーム (CONTINUATION が続く可能性がある)
  PP: PUSH_PROMISE フレーム (CONTINUATION が続く可能性がある)
  ES: END_STREAM フラグ
  R:  RST_STREAM フレーム
```

自分の理解のために表にしてみた。
HEADERSを送信できる状態は、その後にCONTINUATIONもDATAも送信できるものとする。

| ストリーム状態 | 送信可能 |遷移する状態|受信可能|
|:-------------|------------------:|:---------:|:---------:|
| idle       | HEADERS<br>PUSH_PROMISE(予約ID)|     open<br>reserved (local)<br>reserved (remote)     |HEADERS<br>PRIORITY|
| reserved (local)     |  HEADERS<br>RST_STREAM<br>PRIORITY  |    half closed (remote)<br>closed    |RST_STREAM<br>PRIORITY<br>WINDOW_UPDATE|
| reserved (remote)     | RST_STREAM<br>PRIORITY<br>WINDOW_UPDATE | half closed (local)<br>closed |HEADERS<br>RST_STREAM<br>PRIORITY|
| open     | HEADERS(END_STREAM)<br>RST_STREAM | half closed (local)<br>half closed (remote)<br>closed| PUSH_PROMISE以外 |
|half closed (local)| RST_STREAM<br>PRIORITY<br>WINDOW_UPDATE| closed |全て可能|
| half closed (remote)     | HEADERS(END_STREAM)<br>RST_STREAM | closed |RST_STREAM<br>PRIORITY<br>WINDOW_UPDATE|
| closed |PRIORITY|reserved|WINDOW_UPDATE(加算する必要あり)|


# half closedとはなにか

ある開いたストリームがclosed状態になるには3つのパターンがある。

+ GETに対するレスポンスなど、双方でデータの送受信を行う場合はEND_STREAMの送信と受信
+ 片方からだけプッシュする場合は、データ送信者のEND_STREAMの送信
+ RST_STREAMの送信か受信

half closedは、**片方がそれ以上DATAを送信しない状態**。(という理解で合ってると思う)

ドラフトの図を見るとhalf closedには二つある。

+ half closed (remote)
+ half closed (local)

remoteは、自分から見て現在のIDのストリームの相手の状態。
localは、自分から見て現在のIDのストリームの状態。


#half closed(remote)

自分は何かを送るが、相手がそれ以上DATAを送らない状態。つまり相手からEND_STREAMを受けた状態。
図の左側は自分からPUSHしてるので、相手は受信するだけなのでこの状態になっている。相手はこれ以上送信してこないので、残りの作業は自分が送りたいものを送りきってEND_STREAMを送信すること。

これは相手が「GET /」を送ってきた後の状態に等しい。(たぶん)
サーバープッシュの場合はPUSH_PROMISEで予約が終わって、これから送りたいものを送る前の状態。

#half closed(local)
自分はこれ以上DATAを送らない状態。つまり自分からEND_STREAMを送った状態。
残りの作業は相手から送られてくる様々なフレームを受信して、END_STREAMが来るまで待つ事。だから表では「全て受信可能」になっている。

これは自分が「GET /」を送った後の状態に等しい。はず。。
サーバープッシュの場合はPUSH_PROMISEで通知を受けて、これからDATAが降ってくるのを待っている状態。


#END_STREAMフラグとRST_STREAM

なぜストリームを終了させるのにEND_STREAMフラグとRST_STREAMがあるのか？
RST_STREAMはキャンセルやエラー処理のための即断を意味するので、基本的にはEND_STREAMフラグで終了させるのが正しい。たぶん。