DOBON.NET DOBON.NETプログラミング掲示板過去ログ

HTTP/1.1 でのチャンクデコード

環境/言語:[OS : Windows 7 / 言語 : Visual Basic 2008 / .NET Framework : 3.0]
分類:[.NET]

【解決したい問題】

いつも大変重宝して利用させて頂いてます。

Visual Basic 2008 にて、TcpListenerクラスを使用して、下記を参考に
Webサーバへの接続を行うブラウザのようなものを作成しています。
→http://dobon.net/vb/dotnet/internet/tcpclientserver.html

こちらについて、HTML/1.0 の接続は全く問題なく行えるのですが
HTTP/1.1 での接続となると、接続するWebサーバによっては、
[Transfer-Encoding: chunked]が強制付加されてしまいます。(解除不可)

その結果、受信自体は行えるのですが、受信すべき文字列以外の情報
(チャンク制御用文字列等)が文字列に代入されてしまいます。

これは、Socketを使う方法でも同様でした。
→http://dobon.net/vb/dotnet/internet/downloadusesocket.html

素直に、WebRequest、WebResponseクラスを使用して受信すれば
チャンクデータが自動でデコードされるのですが、
こちらのクラスは若干IEに依存するような気がしており、できれば、
TcpListenerか、Socketクラスを用いつつうまくチャンクデータがデコード
(チャンク制御用の文字列を削除して本来の受信文字列に戻す)
のですが、何かお手軽な方法があれば教えてください

【解決するために何をしたか】

Perlで記載されたチャンクデータをデコードするコードを見つけたのですが
なんとか移植できないかがんばってます・・
→http://www.kasai.fm/perlHTTP/decode.html

HTTP応答については下記を参照しています
→http://www.tohoho-web.com/ex/http.htm

よろしくお願いします <m(__)m>
2011/01/16(Sun) 14:51:15 編集(投稿者)

■No28019に返信(karasumaさんの記事)
> 何かお手軽な方法があれば教えてください
お手軽な方法は、HttpWebRequest/Response を使う事ですが、
それはやりたくないのですよね。

だとすると、各チャンクを順に拾い集めてデコードする事になりますが、
分からないのはアルゴリズムでしょうか。それともコーディングの方でしょうか。


レスポンスボディがたとえば
 36-0D-0A-68-65-6C-6C-6F 20-0D-0A-35-0D-0A-77-6F
 72-6C-64-0D-0A-30-0D-0A 0D-0A
というバイナリ、すなわち『
6
hello
5
world
0
』のようなテキストとして得られた場合には、処理手順としてはこんな感じです。


(1) ヘッダー部で、「Transfer-Encoding: chunked」あるいは
 「Transfer-Encoding: chunked;追加パラメータ」が
 指定されていることを確認する。
 この時、Trailer ヘッダーがあればその内容も確認しておくとなお良い。
(2) ボディのバイナリから、最初に現れる CRLF までのバイナリを得る。
 上記では、1 バイトの &H36。
(3) 2で得たバイナリを Ascii としてデコードして文字列に変換。
 今回の例では "6"。
(4) 3で得た文字列をセミコロン(;)で千切る(Split メソッド等を利用)。
 セミコロンより前にある最初の文字列は、チャンクサイズを表す
 16進数表記の値を示している。セミコロン以降はエクステンション。
 今回の例ではチャンクサイズが 6 バイト、エクステンションの指定は無し。
 なお、エクステンションとしては、hoge=value や hoge="value" あるいは
 単に hoge といった形式で指定できる事になっているが、あまり利用されていない。
(5) 4で得たチャンクサイズ分だけボディのバイナリを読み進め、それを
 適当な場所――List(Of Byte), FileStream, MemoryStream 等――に転記する。
 この場合は、0A-68-65-6C-6F-20 の 6 バイトであり、文字列 "hello "に相当。
(6) チャンクの末尾には 2 バイトの CR LF が付くが、それは読み捨てる。
(7) その後に続くバイナリから、2〜5 の手順を繰り返し、
 次のチャンクサイズを見つけ、データを取り出し、ため込んでいく。
 今回の場合、次のチャンクは 5 バイトの 77-6F-72-6C-64 すなわち "world" 。
(8) チャンクサイズが 0 になるまで手順 7 を続けていく。
 0 バイトのチャンクが出れば、ボディ部はそこで終了。
 今回の場合、これによって "hello world" というボディを得られる事になる。
(9) 最後の 0 バイトのチャンクが現れた後(CR LF の後)に、オプションの
 トレーラーとして、一部のエンティティヘッダ(たとえば Content-Length など)が
 付与されている事があるので、必要に応じてそれらも別途拾い集めるようにする。
 (ヘッダー部に Trailer が無くても、トレーラーは付与される可能性がある)
2011/01/16(Sun) 18:32:06 編集(投稿者)

魔界の仮面弁士さん
コメント&解説ありがとうございました。
頂いた情報を基にもう少しこちらでも処理方法を考えてみたいと思います。
遅くなりましたが、プログラムは未完成なのですが、
仕組みは理解できましたので、ステータスを変更させて頂きます。

ありがとうございました!
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板