/
358.txt
296 lines (211 loc) · 16.6 KB
/
358.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
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
* 仕様書
[REFS[
- [78] [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>
- [79] [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-4.1>
- [29] [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.1>
- [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-6.5.2>
- [8] '''[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.6>'''
- [34] '''[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-8.2>'''
- [70] [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-10.4>
- [76] [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-10.5>
]REFS]
* 意味
[35] [[HTTP/2]] [[server push]] は、
[[応答]]とそれに対応する「[RUBYB[約束]@en[promised]]」[[要求]]を、
先に[[クライアント]]が開始した[[要求]]に関連付ける形で[[サーバー]]から予め送信
([[push]]) するものです [SRC[>>34]]。
[36] [[server push]] は、[[クライアント]]が元の[[要求]]に対する[[応答]]を完全に処理するために当該[[応答]]が必要になるであろうとわかっている場合に便利です
[SRC[>>34]]。
[55] [[server push]] は、意味的には[[クライアント]]の[[要求]]に[[サーバー]]が[[応答]]を返す通常の場合と同じですが、
[[要求]]を[[クライアント]]ではなく[[サーバー]]が ([[クライアント]]へと)
[CODE[[[PUSH_PROMISE]]]] [[フレーム]]により送信します [SRC[>>34]]。
[52] [[クライアント]]は、 [[push]] できません [SRC[>>34]]。
* 約束要求
[44] [[サーバー]]から[[クライアント]]へと送信する[[要求]]を、
[DFN[[RUBYB[[[約束要求]]]@en[promised request]]]]といいます。
[39] [[約束要求]]は、[[要求本体]]を含んでは[['''なりません''']] [SRC[>>34]]。
[56] [CODE[[[PUSH_PROMISE]]]] [[フレーム]] (と [CODE[[[CONTINUATION]]]]
[[フレーム]]) が、[[要求]]の [[header block]] を含みます。
[[要求]]の[[ヘッダー]]を[[妥当]]かつ完全に含まなければ[['''なりません''']]。 [SRC[>>34]]
[49] [[サーバー]]は、当該[[サーバー]]が権限を有する ([[authoritative]])
[CODE(HTTP)@en[[[:authority]]]] [[疑似ヘッダー]]値を含めなければ[['''なりません''']]
[SRC[>>34]]。
[37] [[約束要求]]は、[[キャッシュ可能]]でなければ[['''なりません''']] [SRC[>>34]]。
[38] [[約束要求]]は、[[安全]]でなければ[['''なりません''']] [SRC[>>34]]。
[58] [[サーバー]]は、 [CODE(HTTP)@en[[[:method]]]] [[疑似ヘッダー]]に[[安全]]で[[キャッシュ可能]]な[[要求メソッド]]を指定しなければ[['''なりません''']] [SRC[>>34]]。
[61] [[サーバー]]は、約束された[[応答]]を参照する[[フレーム]]を送信する前に、
[CODE(HTTP)@en[[[PUSH_PROMISE]]]] [[フレーム]]を送信する[['''べきです''']]。
これにより[[クライアント]]が [CODE[[[PUSH_PROMISE]]]] [[フレーム]]を送信する前に別途[[要求]]を発行することを防ぐことができます。 [SRC[>>34]]
[EG[
[62] 例えば [CODE(HTTP)@en[[[DATA]]]] [[フレーム]]に[[画像]]を埋め込むリンクが含まれているなら、
それよりも前に当該[[画像]]の [CODE[[[PUSH_PROMISE]]]] [[フレーム]]を送信することにできます。 [SRC[>>34]]
]EG]
[71] 複数の[[著者]]の[[資源]]を提供する[[サーバー]]は、
他の[[著者]]の管轄下のはずの[[資源]]を[[プッシュ]]できてしまわないようにしなければ[['''なりません''']] [SRC[>>70]]。
;; [72] [[レンタルサーバー]]や[[クラウド]]サービスの[[逆串]]などで注意が必要です。
* プッシュ応答
[48] [[約束要求]]に続いて[[サーバー]]から[[クライアント]]へと送信する[[応答]]を、
[DFN[[RUBYB[プッシュ応答]@en[pushed response]]]]といいます。
[65] [[サーバー]]は [CODE[[[PUSH_PROMISE]]]] [[フレーム]]
(と [CODE[[[CONTINUATION]]]] [[フレーム]]) に続けて
(同じ[[ストリーム]で) [[プッシュ応答]]を配送開始できます [SRC[>>34]]。
* 処理
[60] [[クライアント]]は、[[約束要求]]に完全で妥当な[[ヘッダー]]の集合が含まれていなければ、
[[ストリームエラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>34]]。
[40] [[クライアント]]は、[[キャッシュ可能]]でない[[約束要求]]を受信したら、
[[ストリームエラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>34]]。
[41] [[クライアント]]は、[[安全]]でない[[約束要求]]を受信したら、
[[ストリームエラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>34]]。
[59] [[クライアント]]は、 [CODE(HTTP)@en[[[:method]]]] [[疑似ヘッダー]]に[[安全]]でない[[要求メソッド]]が指定されていれば、
[[ストリームエラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>34]]。
;; [43] [[クライアント]]が新しい[[要求メソッド]]が[[安全]]と知っていなければ、
エラーになります [SRC[>>34]]。
[42] [[クライアント]]は、[[要求本体]]の存在を示した[[約束要求]]を受信したら、
[[ストリームエラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>34]]。
[50] [[クライアント]]は、[[サーバー]]が権限を有する ([[authoritative]])
か[[プロキシ]]であって対応する[[要求]]に関する[[プッシュ応答]]を提供するよう設定されていることを検証しなければ[['''なりません''']]。
それ以外の値の [CODE(HTTP)@en[[[:authority]]]] [[疑似ヘッダー]]が含まれていたら、
[[ストリームエラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>34]]。
[EG[
[69] [[DNS-ID]] または[[共通名]]として [CODE[[[example.com]]]]
が指定された[[証明書]]を使っている[[サーバー]]の場合、
[CODE[https://www.example.org/doc]] の[[プッシュ応答]]を提供してはなりません。 [SRC[>>34]]
]EG]
[45] [[プッシュ応答]]は、[[キャッシュ可能]]なら、
[[クライアント]]の [[HTTPキャッシュ]]に[[蓄積]]できます [SRC[>>34]]。
[46] [[プッシュ応答]]は、[[ストリーム]]が [[open]]
である間、[[起源サーバー]]で成功裏に[[検証]]されたものとみなします [SRC[>>34]]。
[47] [[プッシュ応答]]は、[[キャッシュ可能]]でなければ、
[[HTTPキャッシュ]]に[[蓄積]]しては[['''なりません''']]。
別途[[応用]]に提供しても構いません。 [SRC[>>34]]
[51] [[中間器]]は、[[サーバー]]からの [[push]] を[[クライアント]]へと[[転送]]しないことにしても構いません。
また[[サーバー]]から送られてこなくても独自に[[クライアント]]に [[push]]
しても構いません。 [SRC[>>34]]
[66] [[クライアント]]は、 [CODE[[[PUSH_PROMISE]]]] [[フレーム]]を受信し、
[[プッシュ応答]]を受け入れることにしたら、
その[[ストリーム]]が閉じられるまでの間、
その[[応答]]に対する[[要求]]を発行する[['''べきではありません''']] [SRC[>>34]]。
[67] [[クライアント]]は、何らかの理由で[[プッシュ応答]]を受信したくない時や、
[[サーバー]]が[[プッシュ応答]]を送信し始めるまでの時間がかかりすぎている時は、
[CODE[[[RST_STREAM]]]] [[フレーム]]に[[誤り符号]] [CODE[[[CANCEL]]]] や
[CODE[[[REFUSED_STREAM]]]] を指定し、当該[[ストリーム識別子]]を指定して送信できます [SRC[>>34]]。
[73] [[サーバー]]が [[authoritative]] でない[[応答]]を[[キャッシュ]]したり、
使ったりしては[['''なりません''']] [SRC[>>70]]。
;; [74] [[authoritative]] かどうかの判定については、 [[HTTP接続]]の再利用の項を参照。
[EG[
[75] 例えば [CODE[[[example.com]]]] の[[サーバー証明書]]を持つ [[TLS接続]]上で
[CODE[https://example.net/]] の[[応答]]が[[プッシュ]]されても、
使ってはなりません。
]EG]
[77] [[クライアント]]は、 [[reserved (remote)]] 状態にある[[ストリーム]]の数を制限する[['''べきです''']]。
超過したら[[ストリームエラー]] [CODE[[[ENHANCE_YOUR_CALM]]]]
とできます。 [SRC[>>76]]
* [CODE(HTTP)@en[PUSH_PROMISE]] フレーム
** 意味
[9] [CODE[[[PUSH_PROMISE]]]] [[フレーム]] ([[フレーム型]] [CODE[[[0x5]]]]) は、
[[peer]] に対して[[ストリーム]]を開始することを予め通知するものです [SRC[>>8]]。
[23] [CODE[[[PUSH_PROMISE]]]] によって予約する順序は、その[[ストリーム]]を利用する順序と一致していなくても構いません [SRC[>>8]]。
** 構文
[57] [[ストリーム識別子]]は、[[要求]]が属する[[ストリーム]]を表します [SRC[>>34]]。
[16] 次の[[フラグ]]があります。
[FIG(list members)[
:[17] [CODE[[[END_HEADERS]]]] ([CODE[[[0x4]]]] = 第2ビット):
設定されていれば、[[header block]] 全体が含まれており、 [CODE[[[CONTINUATION]]]]
[[フレーム]]が続かないことを表します [SRC[>>8]]。
[18] 設定されていなければ、同じ[[ストリーム]]で [CODE[[[CONTINUATION]]]]
[[フレーム]]が続かなければ[['''なりません''']] [SRC[>>8]]。
:[20] [CODE[[[PADDED]]]] ([CODE[[[0x8]]]] = 第3ビット):
設定されていれば、詰め長欄と詰めが存在することを示します [SRC[>>8]]。
]FIG]
[80] 他の[[フラグ]]は、0 でなければ[['''なりません''']]。
[[受信者]]は、無視しなければ[['''なりません''']]。 [SRC[>>79]]
[FIG(packet)[
:width:8
= 1 0
= 1 0
= 1 [CODE[[[END_HEADERS]]]]
= 1 [CODE[[[PADDED]]]]
= 1 0
= 1 0
= 1 0
= 1 0
]FIG]
[11] [[payload]] は、次の欄で構成されます。
[12] [RUBYB[詰め長]@en[pad length]]は、[[フレーム]]の詰めの長さを[[バイト]]単位で指定する
8ビットの欄です [SRC[>>8]]。
[CODE[[[PADDED]]]] [[フラグ]]が設定されている場合のみ存在します [SRC[>>8]]。
;; [30] 値は0でも構いません。値が実際の[[詰め]]の長さを超えることは禁止されていませんが、
当然正しく処理できませんし、可能な長さを超えるなら[[接続エラー]]となります。
[13] R は、予約されている1ビットです [SRC[>>8]]。
[10] [RUBYB[約束ストリームID]@en[promised stream ID]]は、
[[送信者]]がで予約する[[ストリーム]]の[[符号無し]]31ビット[[ストリーム識別子]]を示します [SRC[>>8]] ([[ネットワークバイト順]] [SRC[>>78]])。
[[送信者]]が作成する次の[[ストリーム]]の識別子として妥当なものでなければ[['''なりません''']]
[SRC[>>8]]。 [[idle]] 状態でなければなりません [SRC[>>8]]。
これは[RUBYB[関連付けられた]@en[associated]][[ストリーム]]を表します [SRC[>>8]]。
[14] [[header block fragment]] は、[[要求ヘッダー]]を含んだ [[header block fragment]]
です [SRC[>>8]]。
[15] [RUBYB[詰め]@en[padding]]は、
[[メッセージ]]の長さを隠すための[[セキュリティー]]機能です。
[[送信者]]は、すべて 0 の[[オクテット]]にしなければ[['''なりません''']]。 [SRC[>>29]]
;; [31] 詰め長の長さより、詰めの最大長は、255バイトです。
[FIG(packet)[
:width:32
= 8 詰め長
= 1 R
= 31 ストリーム識別子
= 88... header block fragment
= 32... 詰め
]FIG]
** 文脈
[64] [CODE[[[PUSH_PROMISE]]]] [[フレーム]]は、
任意の[[クライアント]]が開始した[[ストリーム]]に対して、
[[サーバー]]が送信することができます [SRC[>>34]]。
[21] [[peer]] が開始した[[ストリーム]]で状態が [[open]] か [[half-closed (remote)]]
である場合にしか送信しては[['''なりません''']] [SRC[>>8, >>34]]。
[3] [[設定]] [CODE[[[SETTINGS_ENABLE_PUSH]]]] が 0 に設定されていれば、
[CODE[[[PUSH_PROMISE]]]] [[フレーム]]を送信しては[['''なりません''']] [SRC[>>1, >>8]]。
[63] [[クライアント]は、 [CODE[[[PUSH_PROMISE]]]] [[フレーム]]を送信しては[['''なりません''']]
[SRC[>>34]]。
** 処理
[4] [[設定]] [CODE[[[SETTINGS_ENABLE_PUSH]]]] を 0 に設定し、
[[acknowledge]] された[[エンドポイント]]は、
[CODE[[[PUSH_PROMISE]]]] [[フレーム]]を受信したら、
[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>1, >>8]]。
[22] 関連付けられた[[ストリーム識別子]]が [CODE[[[0x0]]]] なら、
[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>8]]。
[28] 関連付けられた[[ストリーム識別子]]が違法 ([[idle]] 状態でない) なら、
[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>8]]。
[25] [[ストリーム]]の状態遷移の項を参照。
[26] [[受信者]]は、[[ストリーム]]の状態が [[open]] でも [[half-closed (local)]]
でもなければ、[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']]
[SRC[>>8]]。
[27] ただし、[CODE[[[RST_STREAM]]]] を送信した後 (の [[closed]] 状態) には、
受信した [CODE[[[PUSH_PROMISE]]]] を処理しなければ[['''なりません''']] [SRC[>>8]]。
[32] [[受信者]]は、[[詰め]]に 0 以外があれば[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]]
としても構いません。 [SRC[>>29]]
[33] [[受信者]]は、詰め長が可能な長さより長ければ、
[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>29]]。
[24] [[受信者]]は、約束された[[ストリーム識別子]]を参照する
[CODE[[[RST_STREAM]]]] [[フレーム]]を返送することで、
約束[[ストリーム]]を拒絶することができます [SRC[>>8]]。
[19] [CODE[[[END_HEADERS]]]] フラグが設定されていない場合、
次の[[フレーム]]が [CODE[[[CONTINUATION]]]] で無いか、
違う[[ストリーム]]なら、[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]]
としなければ[['''なりません''']] [SRC[>>8]]。
[53] [[サーバー]]は、[CODE(HTTP)@en[[[PUSH_PROMISE]]]] [[フレーム]]を受信したら、
[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']] [SRC[>>34]]。
* 設定
[2] [DFN[[CODE[[[SETTINGS_ENABLE_PUSH]]]]]] ([CODE[[[0x2]]]]) は、
[[server push]] を無効化するために使うことができます。 [SRC[>>1]]
[5] 値 1 は、 [[server push]] を認めることを表します。これは初期値です。 [SRC[>>1]]
[6] 値 0 は、 [[server push]] を認めないことを表します [SRC[>>34]]。
[7] [CODE[[[1]]]] と [CODE[[[0]]]] 以外の値は、[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]]
としなければ[['''なりません''']] [SRC[>>1]]。
[54] [[クライアント]]は、 [CODE(HTTP)[[[SETTINGS_ENABLE_PUSH]]]]
が [CODE[[[0]]]] 以外の値に設定されようとしたら、
拒絶して[[接続エラー]] [CODE[[[PROTOCOL_ERROR]]]] としなければ[['''なりません''']]
[SRC[>>34]]。
[68] [[クライアント]]は、[[設定]] [CODE[[[SETTINGS_MAX_CONCURRENT_STREAMS]]]]
によって[[サーバー]]が[[並行]]してプッシュできる[[応答]]の数を制限できます。
0 を設定することで、[[server push]] のための[[ストリーム]]の作成を抑制できます。
ただし [CODE[[[PUSH_PROMISE]]]] [[フレーム]]の送信を禁止するものではありません。 [SRC[>>34]]