Chunked Transferとは
一般にHTTP KeepAliveを利用するには、レスポンスのボディがどこで終わり、次のレスポンスがどこから始まるかをクライアントが知る必要があります、そのためHTTP/1.0ではKeepAliveを行う為にボディの長さをContent-Lengthをヘッダに入れなければなりませんでしたが、サイズを測るためにデータをすべてメモリに読み込むなどの処理が必要になり、レスポンス開始までの時間もかかります。(一般的なアプリケーションにはあまり影響がありませんが)
そこでHTTP/1.1ではChunked Transferという仕組みが入っていて、事前に全体のレスポンスの長さが分からなくても、chunk=固まり毎にサイズを記してレスポンスを返していき、最後に0byteと送信することで、コンテンツの切れ目がわかるようになっています。
HTTP/1.1 200 OK
Date: Fri, 24 May 2013 05:39:21 GMT
Server: Plack::Handler::Monoceros
Content-Type: text/plain
Transfer-Encoding: chunked
78
aaaaa......aaaaa
1e
bbb....bbbbbbb
9
ccccccccc
0
上の「78」「1e」「9」「0」がChunkのサイズになります。16進数で書かれていて、それぞれ「120byte」「30byte」「9byte」「0byte」となってます
MonocerosもContent-Lengthが指定されていない場合、Chunked Transferを使う事でKeepAlive通信ができるようになっています。ちなみに、アプリケーションからのレスポンスボディを複数の要素が入っている配列にするとそれぞれ別のchunkとして送り出します。Starmanも同様です。
sub {
[200, ['Content-Type'=>'text/plain'],[
'a'x120,
'b'x30,
'c'x9
]]
}
Chunkのビジュアライズ
前置きはこれくらいにして、実際のサーバからのレスポンスがどのように分割されて送られて来ているのか調べるツールを書いてみました。
github https://github.com/kazeburo/chunkview
中身はだいぶFurlからのコピペです。
使い方
$ git clone https://github.com/kazeburo/chunkview
$ cd chunkview
$ carton install
$ carton exec -- ./chunkview.pl [url]
上のMonocerosサーバに向けて実行すると
$ carton exec -- ./chunkview.pl http://localhost:5000/
* Chunk View
** Headers
transfer-encoding: chunked
content-encoding:
content-length:
server: Plack::Handler::Monoceros
** chunk table
.------------------------------------------.
| chunk size | byte | content |
+------------+------+----------------------+
| 78 | 120 | aaaaaaaaaaaaaaaaaaaa |
| 1e | 30 | bbbbbbbbbbbbbbbbbbbb |
| 9 | 9 | ccccccccc |
| 0 | 0 | |
'------------+------+----------------------'
と取れます。ふむふむ。
調子乗って他のサーバにも実行してみます。まずYahoo!
$ ./chunkview.pl http://www.yahoo.co.jp/
* Chunk View
** Headers
transfer-encoding: chunked
content-encoding: gzip
content-length:
server:
** chunk table
.---------------------------------------------------.
| chunk size | byte | content |
+------------+-------+------------------------------+
| 00084c9 | 33993 | <!DOCTYPE HTML PUBLI(128637) |
| 0 | 0 | |
'------------+-------+------------------------------'
gzipが使われた上で、1つのchunkに収まっています。contentのカッコ内は圧縮展開後のサイズです
次、はてなブックマーク
$ ./chunkview.pl http://b.hatena.ne.jp/
* Chunk View
** Headers
transfer-encoding: chunked
content-encoding: gzip
content-length:
server: nginx/0.8.52
** chunk table
.------------------------------------------------------------------.
| chunk size | byte | content |
+------------+-------+---------------------------------------------+
| 56f | 1391 | <!DOCTYPE html>%0A<htm(3533) |
| 47e | 1150 | + '?&login_date=' +(2896) |
| 6b7 | 1719 | name="q" type="text(5792) |
| 223 | 547 | </script>%0A(2896) |
| 9be | 2494 | %E7%94%98%E3%81%84%E7.....%9D%E3%81(14480) |
| 7cd | 1997 | ass="date">2013/05/2(11584) |
| 4256 | 16982 | %81%8C%E5%87%BA%E3%82%8B%..E3%81%AB(121682) |
| 0 | 0 | |
'------------+-------+---------------------------------------------'
細かく分かれて転送されてきますね。
次、livedoorblog
$ ./chunkview.pl http://blog.livedoor.jp/staff/
* Chunk View
** Headers
transfer-encoding: chunked
content-encoding: gzip
content-length:
server: Plack::Handler::Starlet
** chunk table
.-------------------------------------------------.
| chunk size | byte | content |
+------------+------+-----------------------------+
| 10 | 16 | (0) |
| 20cd | 8397 | <!DOCTYPE html PUBLI(33005) |
| 26a | 618 | <div class="plugin-r(2896) |
| 706 | 1798 | f/archives/51801785.(8235) |
| 0 | 0 | |
'------------+------+-----------------------------'
なにやら最初の16byteがあやしいです。gzip展開すると0byteです。
実はここにはRFC 1952で仕様化されてるgzipのヘッダだけが収まっています。なんとなく無駄っぽい動作。Naverまとめだと
./chunkview.pl http://matome.naver.jp/
* Chunk View
** Headers
transfer-encoding: chunked
content-encoding: gzip
content-length:
server: Apache
** chunk table
.----------------------------------------------------------------.
| chunk size | byte | content |
+------------+------+--------------------------------------------+
| 10 | 16 | (0) |
| b60 | 2912 | <!DOCTYPE html>%0D%0A<ht(8184) |
< 略 >
| 4dc | 1244 | "NL:matomeimage" ><i(8184) |
| 3d7 | 983 | %0D%0A<p class="mdSubMTM(4231) |
| a | 10 | (0) |
| 0 | 0 | |
'------------+------+--------------------------------------------'
最後のフッタまで別chunkになってる。Apacheかその下のアプリケーションサーバの仕様なんですかね。
まとめとアップデートのお知らせ
ちなみにこの 16byteのchunkはPlack::Middleware::Deflaterでも生成されることが分かったのでバッファして次のchunkと一緒書き出されるようにして先ほどリリースしました。
どうぞご利用ください