-
Notifications
You must be signed in to change notification settings - Fork 4
/
198.txt
425 lines (325 loc) · 20.4 KB
/
198.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
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
[23] [DFN[[CODE(HTTP)@en[[[chunked]]]]]] は、
[[payload body]] を複数の[[塊]] ([[chunk]]) の連続体として表現する[[転送符号化]]です。
[24] [[塊]]のデータの長さはそれぞれの[[塊]]に指定します。そのため、
事前に [[payload body]] 全体の長さが分からなくても、
準備のできたデータから順に送信を開始することができますし、
どこまでが当該[[メッセージ]]に含まれるデータの一部なのかを明確にすることができます。
[414] [[HTTP/1.1]] は [CODE(HTTP)@en[[[chunked]]]] への対応を義務付けています。
[[HTTP/0.9]]、[[HTTP/1.0]]、[[HTTP/2]] では使えません。
* 仕様書
[REFS[
- [413] '''[CITE@en[RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing]] ([TIME[2014-06-07 01:59:35 +09:00]] 版) <https://tools.ietf.org/html/rfc7230#section-4.1>'''
- [25] [CITE@en[RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing]] ([TIME[2014-06-07 01:59:35 +09:00]] 版) <https://tools.ietf.org/html/rfc7230#page-29>
- [31] [CITE@en[RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing]] ([TIME[2014-06-07 01:59:35 +09:00]] 版) <https://tools.ietf.org/html/rfc7230#section-3.3.3>
- [16] [CITE@en[RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing]] ([TIME[2014-09-11 10:00:03 +09:00]] 版) <https://tools.ietf.org/html/rfc7230#section-3.4>
- [33] [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.1>
]REFS]
* 構文
[415] [CODE(HTTP)@en[[[chunked]]]] [[符号化]]されている場合、
[[メッセージ本体]]は、[[塊]]、[[トレーラー部]]、[[CRLF]]
によって構成されます [SRC[>>413]]。
[419] [RUBYB[[[塊]]]@en[chunk]]は、最後の[[塊]]だけ特別な形になります。
それより前に任意の個数の[[塊]]を置けます。
[FIG(railroad)[
= *
== [[塊]]
= 最後の[[塊]]
= *
== [[ヘッダー]]
== [[CRLF]]
= [[CRLF]]
]FIG]
[416] 最後以外の[[塊]]は、サイズ、拡張、[[CRLF]]、データ、[[CRLF]]
によって構成されます [SRC[>>413]]。
[FIG(railroad)[
= +
== [[十六進数字]]
= *
== 拡張 >>423
= [[CRLF]]
= *
== [[オクテット]]
= [[CRLF]]
]FIG]
[420] 最後の[[塊]]は、サイズ、拡張、[[CRLF]] によって構成されます [SRC[>>413]]。
[FIG(railroad)[
= +
== [CODE[[[0]]]]
= *
== 拡張 >>423
= [[CRLF]]
]FIG]
[417] サイズは、1文字以上の[[十六進数字]]の列によって構成され、
データのオクテット数を[[16進数]]として表しています [SRC[>>413]]。
ただし最後の[[塊]]のサイズは、 [[0]] でなければいけません [SRC[>>413]]。
;; [421] [[先導0]]は禁止されていません。
[418] データは、1[[オクテット]]以上の[[オクテット列]]です。
;; [429] 従って最後以外の[[塊]]のサイズは必ず [[0]] 以外となります。
* 文脈
[30] [CODE(HTTP)@en[[[chunked]]]] [[転送符号化]]は、
[CODE(HTTP)@en[[[chunked]]]] という値を [CODE(HTTP)@en[[[Transfer-Encoding:]]]]
[[ヘッダー]]に指定することにより、[[メッセージ本体]]に適用することができます。
[27] [CODE(HTTP)@en[[[chunked]]]] を同じ[[メッセージ本体]]に複数回適用しては[['''なりません''']]
[SRC[>>25]]。
[28] 複数の[[転送符号化]]が適用される時は、[CODE(HTTP)@en[[[chunked]]]]
を最後に適用しなければ[['''なりません''']] [SRC[>>25]]。
[29] [CODE(HTTP)@en[[[chunked]]]] 以外の[[転送符号化]]を適用するときは、
[[接続]]を閉じることによって[[メッセージ]]を終端するのでなければ、
最後に [CODE(HTTP)@en[[[chunked]]]] を適用しなければ[['''なりません''']] [SRC[>>25]]。
[32] [CODE(HTTP)@en[[[chunked]]]] 以外の[[転送符号化]]が用いられている場合を除き、
事前に[[メッセージ本体]]の長さが分かっている時には、 [CODE(HTTP)@en[[[chunked]]]]
よりも [CODE(HTTP)[[[Content-Length:]]]] を使う[['''べきです''']]。
実装によっては [CODE(HTTP)[[[chunked]]]] に対応していても、
[CODE(HTTP)[[[411]]]] で応答することがあります。 [SRC[>>31]]
[34] [[HTTP/2]] では [CODE(HTTP)@en[[[chunked]]]] を使っては[['''なりません''']] [SRC[>>33]]。
;; [35] [CODE(HTTP)@en[[[DATA]]]] [[フレーム]]の列が、 [[chunked]] の列に相当しています。
* 構文解析
[26] [[HTTP/1.1]] [[受信者]]は、 [CODE(HTTP)@en[[[chunked]]]]
[[転送符号化]]を[[構文解析]]して[[復号]]できなければ[['''なりません''']] [SRC[>>25]]。
;; [422] [[HTTP/1.0]] までは[[転送符号化]]は存在せず、
[CODE(HTTP)@en[[[chunked]]]] [[符号化]]もありませんでした。
[[HTTP/1.0]] と分かっている相手に [CODE(HTTP)[[[chunked]]]]
[[符号化]]を使用することは認められていませんし、
意図通り解釈されることは期待できません。ただし [[HTTP/1.0]]
を[[プロトコルの版]]とする[[メッセージ]]で [CODE(HTTP)@en[[[Transfer-Encoding:]]]]
[[ヘッダー]]が含まれていて [CODE(HTTP)@en[[[chunked]]]]
が指定されている時に、どう解釈するべきなのかは明確ではありません。
[412] 長さが[[零]]の[[塊]]を受信していない場合、[[メッセージ]]は[[不完全]]です [SRC[>>31]]。
[15] 入力が妥当な [CODE(HTTP)@en[[[chunked]]]] [[符号化]]されたデータになっていないときどう処理するべきなのかは不明瞭ですが、
[[不完全メッセージ]]として扱うべきであるとの言及があります [SRC[>>16]]。
* 拡張
[423] [[塊]]には拡張を0個以上指定できます [SRC[>>413]]。
[424] 拡張は、 [CODE[[[;]]]]、名前、[CODE[[[=]]]]、値を並べたものです。
ただし [CODE[[[=]]]] と値は省略できます。 [SRC[>>413]]
[[ヘッダー]]内ではありませんから、 [[OWS]] は認められていません。
[425] 名前は[[字句]]です。値は[[字句]]または[[引用文字列]]です。 [SRC[>>413]]
[FIG(railroad)[
= [CODE[[[;]]]]
= [[字句]]
= [CODE[[[=]]]]
= |
== [[字句]]
== [[引用文字列]]
]FIG]
[426] 拡張は、[[署名]]や[[ハッシュ値]]を入れたり、メッセージのサイズをランダムに変化させたり、
[[long polling]] など特別な目的で使ったりすることが想定されているようです。 [SRC[>>413]]
しかし現時点で利用例はありません。
;; [13] >>435 で [CODE(HTTP)@en[[[progress]]]] が提案されていますが、
実装されるには至っていないようです。
[REFS[
- [435] [CITE@en[draft-lnageleisen-http-chunked-progress-00 - Chunked Progress extension to HTTP]]
( ([TIME[2014-07-13 15:10:59 +09:00]] 版))
<http://tools.ietf.org/html/draft-lnageleisen-http-chunked-progress-00>
- [14] [CITE@en[lloeki/http-chunked-progress]] ([TIME[2014-09-18 15:32:08 +09:00]] 版) <https://github.com/lloeki/http-chunked-progress>
]REFS]
;; [36] [[HTTP/2]] で [CODE(HTTP)@en[[[chunked]]]] が禁止されたことで、
今後新たな拡張が規定されることはほとんどあり得ないでしょう。
[427] [[受信者]]は、認識できない拡張を無視しなければ[['''なりません''']]。
[[鯖]]は、[[要求]]中の拡張の合計長を適当と考える長さに制限し、
それを超えたら [CODE(HTTP)[[[4xx]]]] を返す[RUBYB[べき]@en[ought to]]です。 [SRC[>>413]]
* トレーラー部
[428] [[トレーラー部]]には、[[ヘッダー]]を含めることができます。
詳しくは[[トレーラー部]]を参照してください。
* 歴史
[1] 塊 (chunked) 符号化は、 [[HTTP/1.1]] で導入された[[転送符号化]]です。
(転送符号化自体、 [[HTTP/1.1]] で導入されたものです。また現時点で利用出来る唯一の転送符号化でもあります。)
[2] HTTP/1.1 は[[持続可能接続]] ([[Keep-Alive]])
を導入しましたが、このためには内容の長さ
(あるいは内容の終了の位置) を知る必要があります。
[[HTTP]] は非常に単純なプロトコルで、 [[HTTP/1.0]]
以前には終了の位置を知る方法はありませんでした。
その代わりに、接続が切れたらそこで終わりでした。
([[Content-Length:欄]]があれば、切れた接続が正常切断だったのかを判断出来ます。)
しかし持続可能接続ではこの方法は使えません。
そこで導入されたのがこの塊転送符号化です。
HTTP/1.1 では塊転送符号化の実装が必須とされています。
(だけど実装が面倒 (というか見たらやる気を失くす。)
なので、塊符号化を実装せず、それだけのために
HTTP/1.1 非対応の [[UA]] も少なくはありません。)
[3] もちろん、 [[Content-Length:欄]]を必ずつけることにすればそれで長さは特定できるのですが、
[[CGI]] 出力のように長さが事前に定まらない
(定まるのを待っていたら時間が掛かる可能性のある)
ことがありますので不便です。
[4] 塊符号化は、符号化の内容を任意の長さの塊に分け、それぞれの塊の最初に塊の長さを書いておきます。一番最後におまけで長さ
0 と書いた塊をつけときます。これだけです。実はそんなに厄介でもありません。
[FIG(quote)[
[FIGCAPTION[
[21] RFC 2616 より、 3.6.1 Chunked Transfer Coding
]FIGCAPTION]
> The chunked encoding modifies the body of a message in order to
transfer it as a series of chunks, each with its own size indicator,
followed by an OPTIONAL trailer containing entity-header fields. This
allows dynamically produced content to be transferred along with the
information necessary for the recipient to verify that it has
received the full message.
chunked (塊) 符号化は、メッセージの本体を、転送のためにいじって
塊の連続とします。各塊は大きさ指示が付きますし、
最後には'''任意'''で、 trailer (おまけ)
実体頭欄を続けることが出来ます。
これにより、動的に生成した内容が、受信者が完全なメッセージを受け取ったか確認するのに必要な情報と共に転送出来るようになります。
[PRE[
Chunked-Body = *chunk
last-chunk
trailer
CRLF
]PRE]
[PRE[
chunk = chunk-size [ chunk-extension ] CRLF
chunk-data CRLF
chunk-size = 1*HEX
last-chunk = 1*("0") [ chunk-extension ] CRLF
]PRE]
[PRE[
chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
chunk-ext-name = token
chunk-ext-val = token | quoted-string
chunk-data = chunk-size(OCTET)
trailer = *(entity-header CRLF)
]PRE]
> The chunk-size field is a string of hex digits indicating the size of
the chunk[INS[-data in octets]].
The chunked encoding is ended by any chunk whose size is
zero, followed by the trailer, which is terminated by an empty line.
chunk-size (塊長) 欄は、 chunk[INS[-data]] の長さを[INS[オクテット単位で]]表す
16進数字の文字列です。
chunked (塊)符号化は、長さ 0 の chunk (塊)、それに続く,
空行で終わる trailer (おまけ)で終わります。
[INS[
訳注: 上記段落での追加部分は Errata (>>8) から補った。
]INS]
> The trailer allows the sender to include additional HTTP header
fields at the end of the message. The Trailer header field can be
used to indicate which header fields are included in a trailer (see
section 14.40).
trailer により、送信者はメッセージの終わりに追加の HTTP 頭領域を
入れることが出来ます。 Trailer 頭領域は trailer に含まれている
頭領域を示すのに使うことが出来ます。 (14.40節参照)
> A server using chunked transfer-coding in a response MUST NOT use the
trailer for any header fields unless at least one of the following is true:
応答に chunked 転送符号化を使うサーバーは
次の条件の一つ以上を満たさずに trailer を使っては'''いけません'''。
> a)the request included a TE header field that indicates "trailers" is
acceptable in the transfer-coding of the response, as described in
section 14.39; or,
a) 14.39節で説明するように、要求が、 「trailers」を応答の転送符号化で
使っても良いと示す TE 頭領域を含んでいる場合
> b)the server is the origin server for the response, the trailer
fields consist entirely of optional metadata, and the recipient
could use the message (in a manner acceptable to the origin server)
without receiving this metadata. In other words, the origin server
is willing to accept the possibility that the trailer fields might
be silently discarded along the path to the client.
b) サーバーが、応答の原サーバーで、 trailer 領域が
完全に任意のメタ情報であって、受信者がそのメタ情報を受信せずとも
(原サーバー的に認められる方法で) メッセージを使うことが出来る場合。
別の言い方をすると、原サーバーが、 trailer 領域がクライアントへの
経路中に黙って捨てられる可能性があることを認める意思があるという場合
> This requirement prevents an interoperability failure when the
message is being received by an HTTP/1.1 (or later) proxy and
forwarded to an HTTP/1.0 recipient. It avoids a situation where
compliance with the protocol would have necessitated a possibly
infinite buffer on the proxy.
この要求事項は、メッセージが HTTP/1.1 (以上) の串が受信して
HTTP/1.0 受信者に転送される時に、相互通信性的に失敗するのを
防ぐものです。これにより、このプロトコルに従うことが、
串で不定バッファーが必要になるかもしれない状況を避けることが出来ます。
> An example process for decoding a Chunked-Body is presented in appendix 19.4.6.
塊本体の復号処理の例を附属書 19.4.6 に示しました。
> All HTTP/1.1 applications MUST be able to receive and decode the
"chunked" transfer-coding, and MUST ignore chunk-extension extensions
they do not understand.
全ての HTTP/1.1 応用は「chunked」転送符号化を受信して復号する
ことが出来なければ'''ならず'''、理解できない chunk-extension (塊拡張)
を無視し'''なければなりません'''。
*** RFC 2068・2616 (HTTP/1.1) 19.4.4; Introduction of Transfer-Encoding
> HTTP/1.1 introduces the Transfer-Encoding header field (section [DEL[14.40]] [INS[14.41]]). Proxies/gateways MUST remove any transfer[INS[-]]coding prior to
forwarding a message via a MIME-compliant protocol.
[17] HTTP/1.1 は Transfer-Encoding 頭欄を導入しました。
串・関門は MIME に従うプロトコルにメッセージを転送する前に
[CODE[transfer-coding]] を解か'''なければなりません'''。
> A process for decoding the "chunked" transfer[INS[-]]coding (section 3.6)
can be represented in pseudo-code as:
[18] "chunked" transfer-coding の復号過程は擬似 code
で次のように表せます。
>
[PRE[
length := 0
read chunk-size, chunk-ext[INS[ension]] (if any) and CRLF
while (chunk-size > 0) {
read chunk-data and CRLF
append chunk-data to entity-body
length := length + chunk-size
read chunk-size and CRLF
}
read entity-header
while (entity-header not empty) {
append entity-header to existing header fields
read entity-header
}
Content-Length := length
Remove "chunked" from Transfer-Encoding
]PRE]
[PRE[
長さ := 0
chunk-size と chunk-extension (あれば) と CRLF を読む
(chunk-size > 0) の間 {
chunk-data と CRLF を読む
chunk-data を entity-body に付加する
長さ := 長さ + chunk-size
chunk-size と CRLF を読む
}
entity-header を読む
(entity-header が空でない) の間 {
entity-header を既存の頭欄に付加
entity-header を読む
}
Content-Length := 長さ
"chunked" を Transfer-Encoding から削除
]PRE]
]FIG]
[5] この塊符号化に関する部分の実装の不具合が問題になったこともありました。
([[Apache]] などの古い版を使っている人は新しい版にしましょう。)
[REFS[
- [8] ''HTTP/1.1 Specification Errata'' <http://purl.org/NET/http-errata#chunk-size>
]REFS]
* 実装
- [9] [[Opera]] 6.05 (Win32) の実装をチェックしてみました。
- [10] 改行が CR や LF 単独でも、適当に解釈するので大体意図した通りになります。その辺は人に優しくの精神でいいかげんに実装してある模様。 chunked-extension は対応していないみたいで致命的。引数が表示されて、その字数分あとの計算がずれてきます。これはかなりやばいバグ。 [[TE:]] 欄の申告通り、 Trailer にも対応しています。ただし表示しないことを確認しただけで、本当に機能するかは不明です。 (機能していることを可視化する適当な方法がないんで。)
[431] chunked-extension に対応していなかった実装は他にもありました [SRC[>>430]]。
[REFS[
- [430] [CITE@en[Bug #14092 for HTTP-Parser: chunked encoding, missing extension support]] ([TIME[2014-09-01 16:28:01 +09:00]] 版) <https://rt.cpan.org/Public/Bug/Display.html?id=14092>
]REFS]
- [11] [[Apache]] は [[CGI]] [[スクリプト]]の出力を可能ならかってに chunked にしてくれます。しかし、 CGI スクリプトが勝手に chunked したデータを吐くのはちゃんと見逃してくれます。 (うっかり二重 chunked なんてことはないようです。)
- [12] [WEAK[2003-10-08 07:31:23 +00:00]] ''[[名無しさん]]'': Mozilla は Trailers を正しく無視してくれますが、頭欄としては認識してくれないっぽい。
[22] [CITE@en[IE9 Beta Minor Changes List - EricLaw's IEInternals - Site Home - MSDN Blogs]]
([TIME[2010-10-05 12:14:43 +09:00]] 版)
<http://blogs.msdn.com/b/ieinternals/archive/2010/09/15/ie9-beta-minor-change-list.aspx>
* 関連
[6] [[HTTP]] と似た仕組みを使う [[SIP]] では、この塊符号化の使用は禁止されています。
[7] >>6 [[RTSP]] も禁止。 [CODE[chunked]] は嫌われ者だねぇ
* メモ
[19]
[CITE[TAKESAKO @ Yet another Cybozu Labs: ニコニコ動画勉強会に行ってきました]] ([TIME[2007-09-10 20:25:31 +09:00]] 版) <http://labs.cybozu.co.jp/blog/takesako/2007/04/nicovideo.html>
[20] [CITE[Chunked + Gzip | Apache | Users]] (Referenced: [TIME[2009-07-17T20:53:20+09:00]])
<http://www.gossamer-threads.com/lists/apache/users/356732>
[432] [CITE@en[draft-maes-lemonade-http-binding-04 - IMAP and SMTP HTTP Binding]]
( ([TIME[2014-08-20 10:08:37 +09:00]] 版))
<http://tools.ietf.org/html/draft-maes-lemonade-http-binding-04#section-2.1.2>
[433] [CITE@en[draft-maes-lemonade-tcp-challenged-environments-01 - Lemonade in TCP Challenged Environments]]
( ([TIME[2014-07-15 16:03:40 +09:00]] 版))
<https://tools.ietf.org/html/draft-maes-lemonade-tcp-challenged-environments-01#page-7>
[434] [CITE@en[draft-maes-lemonade-p-imap-12 - Push Extensions to the IMAP Protocol (P-IMAP)]]
( ([TIME[2014-08-24 09:14:38 +09:00]] 版))
<http://tools.ietf.org/html/draft-maes-lemonade-p-imap-12#page-47>
[436] [CITE@en[RFC 3507 - Internet Content Adaptation Protocol (ICAP)]]
( ([TIME[2014-06-08 07:17:07 +09:00]] 版))
<http://tools.ietf.org/html/rfc3507#section-4.4>
[437] [CITE@en[RFC 4387 - Internet X.509 Public Key Infrastructure Operational Protocols: Certificate Store Access via HTTP]]
( ([TIME[2014-06-08 08:24:17 +09:00]] 版))
<http://tools.ietf.org/html/rfc4387#section-2.5.4>
[37] [CITE@en[chunking without chunking]]
([[Adrien de Croy]] 著, [TIME[2009-06-17 15:40:10 +09:00]] 版)
<https://lists.w3.org/Archives/Public/ietf-http-wg/2009AprJun/0717.html>
[38] [CITE[How to enable chunked transfer encoding with IIS]]
([TIME[2015-08-08 00:37:36 +09:00]] 版)
<https://support.microsoft.com/en-us/kb/278998>