/
346.txt
274 lines (199 loc) · 15.8 KB
/
346.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
[2] [DFN[[RUBYB[[[ストリーム]]]@en[stream]]]]は、[[HTTP/2接続]]中の独立した[[フレーム]]の[RUBYB[双方向の流れ]@en[bidirectional flow]] (列) です [SRC[>>1, >>3]]。
* 仕様書
[REFS[
- [1] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-2.2>
- [3] '''[CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-5>'''
-- [71] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-5.4.2>
-- [75] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-5.5>
- [77] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-6.5.2>
]REFS]
* プロトコル
[4] [[HTTP/2接続]]は、並行して複数の[[フレーム]]を開くことができます。
つまり複数の[[ストリーム]]の[[フレーム]]を混在させて送受信できます。 [SRC[>>3]]
[5] [[ストリーム]]は、[[サーバー]]と[[クライアント]]のどちらからも確立したり閉じたりできますし、
一方だけで使ったり、両方で使ったりできます。 [SRC[>>3]]
[7] [[HTTP/2接続]]の開始の時点では、[[ストリーム]]はありません。ただし
[[HTTP/1.1]] から [CODE(HTTP)@en[[[Upgrade:]] [[h2c]]]] で [[HTTP/2]]
で切り替えた場合は、[[ストリーム識別子]] [CODE[[[0x1]]]] が使われた状態となります。
;; [[HTTP/2接続]]参照。
[65] [[エンドポイント]]は、各[[ストリーム]]の次の情報を保持します。
[FIG(list members)[
:[[ストリーム識別子]] [SRC[>>3]]:[[符号無し]]31ビット[[整数]]。
:開始した [[peer]]:[[ストリーム識別子]]が[[奇数]]なら[[クライアント]]、
[[偶数]]なら[[サーバー]]です [SRC[>>3]]。
:状態:状態遷移図上の状態のいずれかです (>>8)。
]FIG]
[6] [[ストリーム]]における[[フレーム]]の順序には意味があり、
[[受信者]]は受信した順序で処理する必要があります。 [SRC[>>3]]
[FIG(short list)[
- [[ストリーム識別子]]
- [[ストリームエラー]]
- [[フロー制御]]
- [[ストリーム優先度]]
]FIG]
* 状態
[8] [[エンドポイント]]は、[[ストリーム]]の[RUBYB[状態]@en[state]]を保持します。
[SRC[>>3]]
[9] [[ストリーム]]の状態は、[[エンドポイント]]がそれぞれ保持しているもので、
[[フレーム]]の転送中は [[peer]] と異なることがあります。 [SRC[>>3]]
また (local) と (remote) のような対となる状態になっていることもあります。
[50] 状態は、[[フレーム]]の送受信で遷移します。単一の[[フレーム]]で複数の状態遷移が発生することもあります。
[63] 未知の[[フレーム型]]の[[フレーム]]は無視して捨てなければ[['''なりません''']]
[SRC[>>3, >>75]]。しかし後述の通り、
指定された[[フレーム]]の種類以外はエラーとなるとの規定もあります。
どちらの規定が優先されるのかは不明ですが、この両文が [[RFC]]
では隣に並んでいるので、無視が優先されると[[エスパー]]できます。
;; [76] 捨てられる[[フレーム]]も、他の要件には影響することがあります。
[[header block]] 参照。
[66] 次の状態があります。
[FIG(list short)[
- [[idle]]
- [[reserved (local)]]
- [[reserved (remote)]]
- [[open]]
- [[half-closed (local)]]
- [[half-closed (remote)]]
- [[closed]]
]FIG]
** idle
[10] [[ストリーム]]は、作成されると [DFN[[[idle]]]] 状態となります [SRC[>>3]]。
;; [11] [[エンドポイント]]は、[[peer]] と協調せずとも自身で[[ストリーム]]を作成できます
[SRC[>>3]]。相手に伝わるまでは、一方のみに[[ストリーム]]が存在する状態となります。
[22] 送信できる[[フレーム]]の種類の制約は明記されていませんが、
[CODE[[[HEADERS]]]] と [CODE[[[PRIORITY]]]] しか送信できないと見られます。
[12] 送受信する[[フレーム]]の種類により、次のような状態遷移があります [SRC[>>3]]。
[FIG(list)[
- [13] [CODE[[[HEADERS]]]] [[フレーム]]を送信または受信すると、 [[open]]
に遷移します。
- [14] 他の[[ストリーム]]で [CODE[[[PUSH_PROMISE]]]] [[フレーム]]を送信し、
その [[Promised Stream ID]] で本[[ストリーム]]が示されていれば、 [[reserved (local)]]
に遷移します。
- [15] 他の[[ストリーム]]で [CODE[[[PUSH_PROMISE]]]] [[フレーム]]を受信し、
その [[Promised Stream ID]] で本[[ストリーム]]が示されていれば、 [[reserved (local)]]
に遷移します。
- [64] 本[[ストリーム]]を開始した [[peer]] がより大きな[[ストリーム識別子]]の[[ストリーム]]を使用したら、
[[closed]] に遷移します。
]FIG]
[16] [CODE[[[HEADERS]]]] と [CODE[[[PRIORITY]]]] 以外の[[フレーム]]を受信したら、
[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>3]]。
** reserved (local)
[17] [CODE[[[PUSH_PROMISE]]]] [[フレーム]]で約束すると、
[[ストリーム]]は [DFN[[[reserved (local)]]]] 状態となります [SRC[>>3]]。
[23] [CODE[[[HEADERS]]]], [CODE[[[RST_STREAM]]]], [CODE[[[PRIORITY]]]]
以外を送信しては[['''なりません''']] [SRC[>>3]]。
[19] 送受信する[[フレーム]]の種類により、次のような状態遷移があります [SRC[>>3]]。
[FIG(list)[
- [20] [CODE[[[HEADERS]]]] [[フレーム]]を送信すると、 [[half-closed (remote)]] に遷移します。
- [21] [CODE[[[RST_STREAM]]]] [[フレーム]]を送信または受信すると、 [[closed]] に遷移します。
]FIG]
[24] [CODE[[[RST_STREAM]]]], [CODE[[[PRIORITY]]]], [CODE[[[WINDOW_UPDATE]]]] 以外の[[フレーム]]を受信したら、
[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>3]]。
** reserved (remote)
[25] [DFN[[[reserved (remote)]]]] 状態は、[[ストリーム]]が [[peer]] により予約されていることを表します [SRC[>>3]]。
[29] [CODE[[[RST_STREAM]]]], [CODE[[[WINDOW_UPDATE]]]], [CODE[[[PRIORITY]]]]
以外を送信しては[['''なりません''']] [SRC[>>3]]。
[26] 送受信する[[フレーム]]の種類により、次のような状態遷移があります [SRC[>>3]]。
[FIG(list)[
- [27] [CODE[[[HEADERS]]]] [[フレーム]]を受信すると、 [[half-closed (local)]] に遷移します。
- [28] [CODE[[[RST_STREAM]]]] [[フレーム]]を送信または受信すると、 [[closed]] に遷移します。
]FIG]
[30] [CODE[[[HEADERS]]]], [CODE[[[RST_STREAM]]]], [CODE[[[PRIORITY]]]]
以外の[[フレーム]]を受信したら、
[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>3]]。
** open
[31] [DFN[[[open]]]] 状態では、任意の[[フレーム]]の送受信ができます。
[34] 送信できる[[フレーム]]の種類の制約はありません [SRC[>>3]]。
[32] 本状態に遷移することになった[[フレーム]]の種類や本状態で送受信する[[フレーム]]の種類により、次のような状態遷移があります [SRC[>>3]]。
[FIG(list)[
- [33] [CODE[[[END_STREAM]]]] フラグが設定された[[フレーム]]を送信すると、
[[half-closed (local)]] 状態に遷移します。
- [35] [CODE[[[END_STREAM]]]] フラグが設定された[[フレーム]]を受信すると、
[[half-closed (remote)]] 状態に遷移します。
- [36] [CODE[[[RST_STREAM]]]] [[フレーム]]を送信または受信すると、 [[closed]] に遷移します。
]FIG]
** half-closed (local)
[37] [DFN[[[half-closed (local)]]]] 状態では、メッセージを送信できませんが、受信するかもしれません。
[38] [CODE[[[WINDOW_UPDATE]]]], [CODE[[[PRIORITY]]]], [CODE[[[RST_STREAM]]]]
以外の[[フレーム]]を送信することはできません [SRC[>>3]]。
;; [42] [[peer]] は任意の[[フレーム]]を送信することができますから、
[CODE[[[WINDOW_UPDATE]]]] [[フレーム]]によって[[フロー制御credit]]提供し続けることが必要かもしれません。
しかし [[peer]] が状態遷移した後なら無視されるかもしれません。 [SRC[>>3]]
[39] 本状態に遷移することになった[[フレーム]]の種類や本状態で送受信する[[フレーム]]の種類により、次のような状態遷移があります [SRC[>>3]]。
[FIG(list)[
- [40] [CODE[[[END_STREAM]]]] フラグが設定された[[フレーム]]を受信すると、
[[closed]] 状態に遷移します。
- [41] [CODE[[[RST_STREAM]]]] [[フレーム]]を送信または受信すると、 [[closed]] に遷移します。
]FIG]
** half-closed (remote)
[43] [DFN[[[half-closed (remote)]]]] 状態は、 [[peer]] が[[フレーム]]の送信をもう行わない[[ストリーム]]を表します [SRC[>>3]]。
[46] 任意の[[フレーム]]を送信できます [SRC[>>3]]。
[44] この状態になると、[[受信者フロー制御窓]]を維持する義務はありません [SRC[>>3]]。
[47] 本状態に遷移することになった[[フレーム]]の種類や本状態で送受信する[[フレーム]]の種類により、次のような状態遷移があります [SRC[>>3]]。
[FIG(list)[
- [48] [CODE[[[END_STREAM]]]] フラグが設定された[[フレーム]]を送信すると、
[[closed]] 状態に遷移します。
- [49] [CODE[[[RST_STREAM]]]] [[フレーム]]を送信または受信すると、 [[closed]] に遷移します。
]FIG]
[45] [CODE[[[WINDOW_UPDATE]]]], [CODE[[[RST_STREAM]]]], [CODE[[[PRIORITY]]]]
以外の[[フレーム]]を受信したら、
[[ストリームエラー]] [DFN[[CODE[[[STREAM_CLOSED]]]]]] としなければ[['''なりません''']] [SRC[>>3]]。
** closed
[51] [DFN[[[closed]]]] 状態は、最終的な状態です [SRC[>>3]]。
[52] [CODE[[[PRIORITY]]]] [[フレーム]]以外を送信しては[['''なりません''']] [SRC[>>3]]。
受信した [CODE[[[PRIORITY]]]] [[フレーム]]は処理する[['''べき''']]ですが、
[[依存性木]]から削除されたら無視できます [SRC[>>3]]。
[18] [CODE[[[RST_STREAM]]]] [[フレーム]]によって [[closed]] に遷移すると、
[[peer]] との状態遷移の時間差が原因で、この状態となった後に[[フレーム]]を受信する可能性もあります [SRC[>>3]]。
[72] [CODE[[[RST_STREAM]]]] [[フレーム]]を送信した後でも、[[フレーム]]を受信する準備をしておかなければ[['''なりません''']] [SRC[>>71]]。
[53] [CODE[[[RST_STREAM]]]] の後に [CODE[[[PRIORITY]]]] 以外の[[フレーム]]を受信したら、
[[ストリームエラー]] [CODE[[[STREAM_CLOSED]]]] としなければ[['''なりません''']] [SRC[>>3]]。
[57] しかし自身が [CODE[[[RST_STREAM]]]] を送信した後に受信した[[フレーム]]は無視しなければ[['''なりません''']]。
ある程度の時間が経過したら、エラーとして扱うことにして構いません。 [SRC[>>3]]
;; [58] [CODE[[[RST_STREAM]]]] を送信した場合、 [[peer]] は既に送信したり、
送信準備をしたりして、取り消せなかった[[フレーム]]が到着する場合があります。 [SRC[>>3]]
[59] [CODE[[[RST_STREAM]]]] を送信した後に受信した[[フロー制御]]対象の[[フレーム]]
([CODE[[[DATA]]]]) は、[[接続フロー制御窓]]の計算に含めます。 [SRC[>>3]]
;; [60] [[フレーム]]が無視されるとしても、相手が [CODE[[[RST_STREAM]]]]
を受信する前に[[フロー制御窓]]で数えてから送信しているはずだからです。 [SRC[>>3]]
[61] [CODE[[[RST_STREAM]]]] を送信した後に [CODE[[[PUSH_PROMISE]]]]
を受信した場合でも、指定された[[ストリーム]]は予約状態となります。
そちらの[[ストリーム]]は不要なら別途 [CODE[[[RST_STREAM]]]] が必要です。 [SRC[>>3]]
[54] [CODE[[[END_STREAM]]]] の後に[[フレーム]]を受信したら、
[[接続エラー]] [CODE[[[STREAM_CLOSED]]]] としなければ[['''なりません''']] [SRC[>>3]]。
[55] ただし、 [CODE[[[WINDOW_UPDATE]]]] や [CODE[[[RST_STREAM]]]]
を受信したら、無視しなければ[['''なりません''']]。
自身が [CODE[[[END_STREAM]]]] を送信してから十分な時間が経ったなら、
[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] としても構いません。 [SRC[>>3]]
;; [56] 自身が [CODE[[[END_STREAM]]]] や [CODE[[[RST_STREAM]]]]
を送信してから相手が受信するまでの時間差があるため、その間に
[CODE[[[WINDOW_UPDATE]]]] や [CODE[[[RST_STREAM]]]] を受信する可能性があります。 [SRC[>>3]]
[73] [CODE[[[RST_STREAM]]]] [[フレーム]]を複数送信する[['''べきではありません''']]が、
1[[RTT]] を過ぎても[[フレーム]]を受信するなら、改めて [CODE[[[RST_STREAM]]]]
[[フレーム]]を送信しても構いません [SRC[>>71]]。
;; [62] [[RFC]] は [[closed]] を1つの状態として表していますが、
実際には何により遷移してきたかで処理を分ける必要があり、また時間経過などで処理が変わる可能性があり、
複雑です。しかも [[RFC]] は「無視する (無視するとは言っていない)」のような変な書き方になっていて難解です。
* 並行性
[67] [[設定]] [DFN[[CODE[[[SETTINGS_MAX_CONCURRENT_STREAMS]]]]]] ([CODE[[[0x3]]]])
は、[[送信者]]が認める並行[[ストリーム]]の最大数を表します [SRC[>>77, >>3]]。
[79] 初期状態は無制限です [SRC[>>77]]。
[78] 不必要に並列性を損なわないため、
この値を 100 [[未満]]とする[RUBYB[べきではありません]@en[recommend]]。 [SRC[>>77]]
[80] 値0は、特別な意味は持ちません。新しい[[ストリーム]]の生成が認められないことを表します。
しかし[[サーバー]]は短い時間に限ってのみ 0 を使う[['''べきです''']]。
[[要求]]を受け付けたくない時は、[[接続]]を閉じる方が適切です。 [SRC[>>77]]
[68] この設定は、[[受信者]]が開始することを認められた[[ストリーム]]の数を示しています。
従って[[クライアント]]は[[サーバー]]の開始する[[ストリーム]]の最大数を指定でき、
[[サーバー]]は[[クライアント]]の開始する[[ストリーム]]の最大数を指定できます。 [SRC[>>3, >>77]]
[81] ここで数に含まれるのは、 [[open]], [[half-closed (local)]], [[half-closed (remote)]]
のいずれかの状態にある[[ストリーム]]です [SRC[>>3]]。
[69] [CODE[[[HEADERS]]]] [[フレーム]]を受信した時、
[[ストリーム]]数上限を超えるなら、
[CODE[[[PROTOCOL_ERROR]]]] または [DFN[[CODE[[[REFUSED_STREAM]]]]]]
の[[ストリームエラー]]としなければ[['''なりません''']]。
どちらを選ぶかは、自動的な再試行を有効にしたいかに依ります。 [SRC[>>3]]
[70] [CODE[[[SETTINGS_MAX_CONCURRENT_STREAMS]]]] の値が現在の[[ストリーム]]の数よりも小さくなる場合は、
新しい値を超えた[[ストリーム]]を閉じることもできますし、
[[ストリーム]]が完了するまで待つこともできます。 [SRC[>>3]]
* 下位層の接続の切断
[74] [[HTTP/2接続]]を参照。