Visual C#を使ってネットワークプログラミングするシリーズ
本シリーズはC#でGoogleマップ等のWebAPIを使おうというのが目的です。
第2回である今回は、HTTPレスポンスヘッダーからコンテンツ内容を判定してみます。
レスポンスヘッダー見てコンテンツ内容判定ツール
概要
指定したURLからbyte配列取得し(16進ダンプ)、
レスポンスヘッダーからコンテンツ内容判定(してテキスト又は画像なら表示)する。
画面構成
レスポンスヘッダーとは
・サーバからクライアントへ送信される。
・200 OKなどといったステータスコードに続けて送信される。
・ヘッダの後に、ボディ(text/htmlならソースの中身)が送信される。
・Content-Length:からデータのサイズが分かる
・Content-Type: からデータの種類が分かる(今回の判定対象9
・Last-Modified: から最終更新日が分かる(更新チェックに使える)
・Server: からサーバの種類が分かる
・例
Connection: keep-alive
Accept-Ranges: bytes
Content-Length: 1106
Cache-Control: max-age=604800
Content-Type: image/gif
Date: Wed, 30 Dec 2009 10:39:23 GMT
ETag: “b0225453a1e8c71:1ff9”
Last-Modified: Mon, 27 Aug 2007 11:56:38 GMT
Server: Microsoft-IIS/6.0
byte配列の取得
・前回と同じ
・今回は16進ダンプ機能を追加。
レスポンスヘッダーの取得
・System.Net名前空間 WebClient.ResponseHeadersプロパティで取得する。
Content-Typeの判定
・WebClient.ResponseHeaders[“Content-Type”]で取得する。
・StringオブジェクトのStartsWith(“image/”)メソッドを利用して、image/で始まるならば画像コンテンツと判定するのが簡単。
・レスポンスヘッダーの例は以下
[テキスト]
text/html、text/plain、text/css、text/xml
[画像]
image/jpeg、image/png、image/gif
[その他]
application/zip、application/pdf
コード
private void button1_Click(object sender, EventArgs e) { /* 表示領域クリア */ textBoxResponseHeader.Text = ""; textBoxContentType.Text = ""; textBox16.Text = ""; textBoxText.Text = ""; labelCharSet.Text = ")"; pictureBox1.Image = null; /* とりあえずbyte配列として取得する */ WebClient myClient = new WebClient(); byte[] bytedata = myClient.DownloadData(textBoxURL.Text); /* ファイルサイズ確認 */ int length = bytedata.Length; ; if (length >= 1024 * 1024) { length = 1024 * 1024; /* とりあえず1Mbyte */ } progressBar1.Minimum = 0; progressBar1.Maximum = length - 1; /* 16進ダンプ */ { int i = 0, j = 0; String tmp16 = ""; /* 16進表示部分 */ String tmpChar = ""; /* 文字列表示部分 */ String tmpLine = ""; /* 1行分の文字列 */ for (i = 0; i < length; i += 1) { /* 1行分の文字列 */ if (i == 0) { tmpLine = " " + "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F rn" + "---------" + "------------------------------------------------" + "----------------" + "rn"; } else if (i % 16 == 0) { tmpLine += String.Format("{0:X08} ", i - 16) + tmp16 + tmpChar + "rn"; tmp16 = ""; tmpChar = ""; } /* 16進表示部分 */ tmp16 += String.Format("{0:X2} ", bytedata[i]); /* 文字列表示部分 */ if ((bytedata[i] <= 0x19) || (bytedata[i] >= 0x7f)) { /* 制御文字は文字列表示を崩すので.にしとく */ tmpChar += "."; } else { tmpChar += ((char)bytedata[i]).ToString(); } progressBar1.Value = i; } /* 最終行は16byte単位に満たない分空白詰めで縦を揃える */ for (j = 0; j < 16 - i % 16; j++) { tmp16 += " "; } tmpLine += String.Format("{0:X08} ", i - i % 16) + tmp16 + tmpChar + "rn"; textBox16.Text += tmpLine; progressBar1.Value = 0; } /* Content-Typeを判定する */ { /* レスポンスヘッダーの取得 */ textBoxResponseHeader.Text += myClient.ResponseHeaders; textBoxContentType.Text = myClient.ResponseHeaders["Content-Type"]; /* Content-Typeの判定 */ String type = myClient.ResponseHeaders["Content-Type"]; if (type.StartsWith("image/")) { /* 画像ならばストリームとして取得して表示 */ Stream httpstream = myClient.OpenRead(textBoxURL.Text); pictureBox1.Image = Image.FromStream(httpstream); httpstream.Close(); } else if (type.StartsWith("text/")) { /* テキストならテキストとして取得して表示 */ /* 文字エンコーディング方式を判定 */ myClient.Encoding = myDetectEncoding(bytedata); textBoxText.Text = myClient.DownloadString(textBoxURL.Text); } } } private Encoding myDetectEncoding(byte[] data) { /* バイト配列をASCIIエンコードで文字列に変換 */ String s = Encoding.ASCII.GetString(data); /* <meta>タグを抽出するための正規表現 */ Match mymatch = Regex.Match(s, @"<metas+[^>]*charsets*=s*([-_w]+)", RegexOptions.IgnoreCase); String e; if(mymatch.Success) { e = mymatch.Groups[1].Value; labelCharSet.Text = Encoding.GetEncoding(e).WebName + ")"; } else { /* <meta>タグから分からないのでshift-jisにしとく */ e = "shift-jis"; labelCharSet.Text = "不明)"; } return Encoding.GetEncoding(e); }
memo
今回のツール作成で得たチップスをメモリます。
チップス集として別記事にまとめるかもしれません。
文字列操作
・StringオブジェクトのStartsWithメソッドで先頭部分が調べられる。
ストリームからImageオブジェクト取得
Stream httpstream = myClient.OpenRead(textBoxURL.Text); pictureBox1.Image = Image.FromStream(httpstream); httpstream.Close();