3 Imports System.Collections.Generic
4 Imports System.Collections.Specialized
8 '''HttpWebRequest,HttpWebResponseを使用した基本的な通信機能を提供する
11 '''プロキシ情報などを設定するため、使用前に静的メソッドInitializeConnectionを呼び出すこと。
12 '''通信方式によって必要になるHTTPヘッダの付加などは、派生クラスで行う。
14 Public Class HttpConnection
18 Private Shared proxy As WebProxy = Nothing
23 Private Shared proxyKind As ProxyType = proxyType.IE
28 Private Shared cookieContainer As New CookieContainer
33 Private Shared isInitialize As Boolean = False
42 '''HttpWebRequestオブジェクトを取得する。パラメータはGET/HEAD/DELETEではクエリに、POST/PUTではエンティティボディに変換される。
45 '''追加で必要となるHTTPヘッダや通信オプションは呼び出し元で付加すること
46 '''(Timeout,AutomaticDecompression,AllowAutoRedirect,UserAgent,ContentType,Accept,HttpRequestHeader.Authorization,カスタムヘッダ)
47 '''POST/PUTでクエリが必要な場合は、requestUriに含めること。
49 '''<param name="method">HTTP通信メソッド(GET/HEAD/POST/PUT/DELETE)</param>
50 '''<param name="requestUri">通信先URI</param>
51 '''<param name="param">GET時のクエリ、またはPOST時のエンティティボディ</param>
52 '''<param name="withCookie">通信にcookieを使用するか</param>
53 '''<returns>引数で指定された内容を反映したHttpWebRequestオブジェクト</returns>
54 Protected Function CreateRequest(ByVal method As String, _
55 ByVal requestUri As Uri, _
56 ByVal param As Dictionary(Of String, String), _
57 ByVal withCookie As Boolean _
59 If Not isInitialize Then Throw New Exception("Sequence error.(not initialized)")
61 'GETメソッドの場合はクエリとurlを結合
62 Dim ub As New UriBuilder(requestUri.AbsoluteUri)
63 If param IsNot Nothing AndAlso (method = "GET" OrElse method = "DELETE" OrElse method = "HEAD") Then
64 ub.Query = CreateQueryString(param)
67 Dim webReq As HttpWebRequest = DirectCast(WebRequest.Create(ub.Uri), HttpWebRequest)
70 If proxyKind <> ProxyType.IE Then webReq.Proxy = proxy
72 webReq.Method = method
73 If method = "POST" OrElse method = "PUT" Then
74 webReq.ContentType = "application/x-www-form-urlencoded"
75 'POST/PUTメソッドの場合は、ボディデータとしてクエリ構成して書き込み
76 Using writer As New StreamWriter(webReq.GetRequestStream)
77 writer.Write(CreateQueryString(param))
81 If withCookie Then webReq.CookieContainer = cookieContainer
83 webReq.Timeout = DefaultTimeout
89 '''HTTPの応答を処理し、引数で指定されたストリームに書き込み
92 '''リダイレクト応答の場合(AllowAutoRedirect=Falseの場合のみ)は、headerInfoインスタンスがあればLocationを追加してリダイレクト先を返却
93 '''WebExceptionはハンドルしていないので、呼び出し元でキャッチすること
94 '''gzipファイルのダウンロードを想定しているため、他形式の場合は伸張時に問題が発生する可能性があります。
96 '''<param name="webRequest">HTTP通信リクエストオブジェクト</param>
97 '''<param name="contentStream">[OUT]HTTP応答のボディストリームのコピー先</param>
98 '''<param name="headerInfo">[IN/OUT]HTTP応答のヘッダ情報。ヘッダ名をキーにして空データのコレクションを渡すことで、該当ヘッダの値をデータに設定して戻す</param>
99 '''<param name="withCookie">通信にcookieを使用する</param>
100 '''<returns>HTTP応答のステータスコード</returns>
101 Protected Function GetResponse(ByVal webRequest As HttpWebRequest, _
102 ByVal contentStream As Stream, _
103 ByVal headerInfo As Dictionary(Of String, String), _
104 ByVal withCookie As Boolean _
107 Using webRes As HttpWebResponse = CType(webRequest.GetResponse(), HttpWebResponse)
108 Dim statusCode As HttpStatusCode = webRes.StatusCode
110 If withCookie Then SaveCookie(webRes.Cookies)
111 'リダイレクト応答の場合は、リダイレクト先を設定
112 GetHeaderInfo(webRes, headerInfo)
114 If webRes.ContentLength > 0 Then
115 'gzipなら応答ストリームの内容は伸張済み。それ以外なら伸張する。
116 If webRes.ContentEncoding = "gzip" OrElse webRes.ContentEncoding = "deflate" Then
117 Using stream As Stream = webRes.GetResponseStream()
118 If stream IsNot Nothing Then CopyStream(stream, contentStream)
121 Using stream As Stream = New System.IO.Compression.GZipStream(webRes.GetResponseStream, Compression.CompressionMode.Decompress)
122 If stream IsNot Nothing Then CopyStream(stream, contentStream)
128 Catch ex As WebException
129 If ex.Status = WebExceptionStatus.ProtocolError Then
130 Dim res As HttpWebResponse = DirectCast(ex.Response, HttpWebResponse)
131 Return res.StatusCode
138 '''HTTPの応答を処理し、応答ボディデータをテキストとして返却する
141 '''リダイレクト応答の場合(AllowAutoRedirect=Falseの場合のみ)は、headerInfoインスタンスがあればLocationを追加してリダイレクト先を返却
142 '''WebExceptionはハンドルしていないので、呼び出し元でキャッチすること
143 '''テキストの文字コードはUTF-8を前提として、エンコードはしていません
145 '''<param name="webRequest">HTTP通信リクエストオブジェクト</param>
146 '''<param name="contentText">[OUT]HTTP応答のボディデータ</param>
147 '''<param name="headerInfo">[IN/OUT]HTTP応答のヘッダ情報。ヘッダ名をキーにして空データのコレクションを渡すことで、該当ヘッダの値をデータに設定して戻す</param>
148 '''<param name="withCookie">通信にcookieを使用する</param>
149 '''<returns>HTTP応答のステータスコード</returns>
150 Protected Function GetResponse(ByVal webRequest As HttpWebRequest, _
151 ByRef contentText As String, _
152 ByVal headerInfo As Dictionary(Of String, String), _
153 ByVal withCookie As Boolean _
156 Using webRes As HttpWebResponse = CType(webRequest.GetResponse(), HttpWebResponse)
157 Dim statusCode As HttpStatusCode = webRes.StatusCode
159 If withCookie Then SaveCookie(webRes.Cookies)
160 'リダイレクト応答の場合は、リダイレクト先を設定
161 GetHeaderInfo(webRes, headerInfo)
163 If contentText Is Nothing Then Throw New ArgumentNullException("contentText")
164 Using sr As StreamReader = New StreamReader(webRes.GetResponseStream)
165 contentText = sr.ReadToEnd()
169 Catch ex As WebException
170 If ex.Status = WebExceptionStatus.ProtocolError Then
171 Dim res As HttpWebResponse = DirectCast(ex.Response, HttpWebResponse)
172 Using sr As StreamReader = New StreamReader(res.GetResponseStream)
173 contentText = sr.ReadToEnd()
175 Return res.StatusCode
182 '''HTTPの応答を処理します。応答ボディデータが不要な用途向け。
185 '''リダイレクト応答の場合(AllowAutoRedirect=Falseの場合のみ)は、headerInfoインスタンスがあればLocationを追加してリダイレクト先を返却
186 '''WebExceptionはハンドルしていないので、呼び出し元でキャッチすること
188 '''<param name="webRequest">HTTP通信リクエストオブジェクト</param>
189 '''<param name="headerInfo">[IN/OUT]HTTP応答のヘッダ情報。ヘッダ名をキーにして空データのコレクションを渡すことで、該当ヘッダの値をデータに設定して戻す</param>
190 '''<param name="withCookie">通信にcookieを使用する</param>
191 '''<returns>HTTP応答のステータスコード</returns>
192 Protected Function GetResponse(ByVal webRequest As HttpWebRequest, _
193 ByVal headerInfo As Dictionary(Of String, String), _
194 ByVal withCookie As Boolean _
197 Using webRes As HttpWebResponse = CType(webRequest.GetResponse(), HttpWebResponse)
198 Dim statusCode As HttpStatusCode = webRes.StatusCode
200 If withCookie Then SaveCookie(webRes.Cookies)
201 'リダイレクト応答の場合は、リダイレクト先を設定
202 GetHeaderInfo(webRes, headerInfo)
205 Catch ex As WebException
206 If ex.Status = WebExceptionStatus.ProtocolError Then
207 Dim res As HttpWebResponse = DirectCast(ex.Response, HttpWebResponse)
208 Return res.StatusCode
215 '''HTTPの応答を処理し、応答ボディデータをBitmapとして返却します
218 '''リダイレクト応答の場合(AllowAutoRedirect=Falseの場合のみ)は、headerInfoインスタンスがあればLocationを追加してリダイレクト先を返却
219 '''WebExceptionはハンドルしていないので、呼び出し元でキャッチすること
221 '''<param name="webRequest">HTTP通信リクエストオブジェクト</param>
222 '''<param name="contentText">[OUT]HTTP応答のボディデータを書き込むBitmap</param>
223 '''<param name="headerInfo">[IN/OUT]HTTP応答のヘッダ情報。ヘッダ名をキーにして空データのコレクションを渡すことで、該当ヘッダの値をデータに設定して戻す</param>
224 '''<param name="withCookie">通信にcookieを使用する</param>
225 '''<returns>HTTP応答のステータスコード</returns>
226 Protected Function GetResponse(ByVal webRequest As HttpWebRequest, _
227 ByRef contentBitmap As Bitmap, _
228 ByVal headerInfo As Dictionary(Of String, String), _
229 ByVal withCookie As Boolean _
232 Using webRes As HttpWebResponse = CType(webRequest.GetResponse(), HttpWebResponse)
233 Dim statusCode As HttpStatusCode = webRes.StatusCode
235 If withCookie Then SaveCookie(webRes.Cookies)
236 'リダイレクト応答の場合は、リダイレクト先を設定
237 GetHeaderInfo(webRes, headerInfo)
238 '応答のストリームをBitmapにして戻す
239 'If webRes.ContentLength > 0 Then contentBitmap = New Bitmap(webRes.GetResponseStream)
240 contentBitmap = New Bitmap(webRes.GetResponseStream)
243 Catch ex As WebException
244 If ex.Status = WebExceptionStatus.ProtocolError Then
245 Dim res As HttpWebResponse = DirectCast(ex.Response, HttpWebResponse)
246 Return res.StatusCode
253 '''クッキーを保存。ホスト名なしのドメインの場合、ドメイン名から先頭のドットを除去して追加しないと再利用されないため
255 Private Sub SaveCookie(ByVal cookieCollection As CookieCollection)
256 For Each ck As Cookie In cookieCollection
257 If ck.Domain.StartsWith(".") Then
258 ck.Domain = ck.Domain.Substring(1, ck.Domain.Length - 1)
259 cookieContainer.Add(ck)
265 '''in/outのストリームインスタンスを受け取り、コピーして返却
267 '''<param name="inStream">コピー元ストリームインスタンス。読み取り可であること</param>
268 '''<param name="outStream">コピー先ストリームインスタンス。書き込み可であること</param>
269 Private Sub CopyStream(ByVal inStream As Stream, ByVal outStream As Stream)
270 If inStream Is Nothing Then Throw New ArgumentNullException("inStream")
271 If outStream Is Nothing Then Throw New ArgumentNullException("outStream")
272 If Not inStream.CanRead Then Throw New ArgumentException("Input stream can not read.")
273 If Not outStream.CanWrite Then Throw New ArgumentException("Output stream can not write.")
274 If inStream.CanSeek AndAlso inStream.Length = 0 Then Throw New ArgumentException("Input stream do not have data.")
277 Dim buffer(1024) As Byte
278 Dim i As Integer = buffer.Length
279 i = inStream.Read(buffer, 0, i)
280 If i = 0 Then Exit Do
281 outStream.Write(buffer, 0, i)
286 '''headerInfoのキー情報で指定されたHTTPヘッダ情報を取得・格納する。redirect応答時はLocationヘッダの内容を追記する
288 '''<param name="webResponse">HTTP応答</param>
289 '''<param name="headerInfo">[IN/OUT]キーにヘッダ名を指定したデータ空のコレクション。取得した値をデータにセットして戻す</param>
290 Private Sub GetHeaderInfo(ByVal webResponse As HttpWebResponse, _
291 ByVal headerInfo As Dictionary(Of String, String))
293 If headerInfo Is Nothing Then Exit Sub
295 If headerInfo.Count > 0 Then
296 Dim keys(headerInfo.Count - 1) As String
297 headerInfo.Keys.CopyTo(keys, 0)
298 For Each key As String In keys
299 If Array.IndexOf(webResponse.Headers.AllKeys, key) > -1 Then
300 headerInfo.Item(key) = webResponse.Headers.Item(key)
302 headerInfo.Item(key) = ""
307 Dim statusCode As HttpStatusCode = webResponse.StatusCode
308 If statusCode = HttpStatusCode.MovedPermanently OrElse _
309 statusCode = HttpStatusCode.Found OrElse _
310 statusCode = HttpStatusCode.SeeOther OrElse _
311 statusCode = HttpStatusCode.TemporaryRedirect Then
312 If headerInfo.ContainsKey("Location") Then
313 headerInfo.Item("Location") = webResponse.Headers.Item("Location")
315 headerInfo.Add("Location", webResponse.Headers.Item("Location"))
321 '''クエリコレクションをkey=value形式の文字列に構成して戻す
323 '''<param name="param">クエリ、またはポストデータとなるkey-valueコレクション</param>
324 Protected Function CreateQueryString(ByVal param As IDictionary(Of String, String)) As String
325 If param Is Nothing OrElse param.Count = 0 Then Return String.Empty
327 Dim query As New StringBuilder
328 For Each key As String In param.Keys
329 query.AppendFormat("{0}={1}&", UrlEncode(key), UrlEncode(param(key)))
331 Return query.ToString(0, query.Length - 1)
335 '''クエリ形式(key1=value1&key2=value2&...)の文字列をkey-valueコレクションに詰め直し
337 '''<param name="queryString">クエリ文字列</param>
338 '''<returns>key-valueのコレクション</returns>
339 Protected Function ParseQueryString(ByVal queryString As String) As NameValueCollection
340 Dim query As New NameValueCollection
341 Dim parts() As String = queryString.Split("&"c)
342 For Each part As String In parts
343 Dim index As Integer = part.IndexOf("="c)
345 query.Add(Uri.UnescapeDataString(part), "")
347 query.Add(Uri.UnescapeDataString(part.Substring(0, index)), Uri.UnescapeDataString(part.Substring(index + 1)))
354 '''2バイト文字も考慮したUrlエンコード
356 '''<param name="str">エンコードする文字列</param>
357 '''<returns>エンコード結果文字列</returns>
358 Protected Function UrlEncode(ByVal stringToEncode As String) As String
359 Const UnreservedChars As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~"
360 Dim sb As New StringBuilder
361 Dim bytes As Byte() = Encoding.UTF8.GetBytes(stringToEncode)
363 For Each b As Byte In bytes
364 If UnreservedChars.IndexOf(Chr(b)) <> -1 Then
367 sb.AppendFormat("%{0:X2}", b)
373 #Region "DefaultTimeout"
377 Private Shared timeout As Integer = 20000
380 '''通信タイムアウト時間(ms)。10~120秒の範囲で指定。範囲外は20秒とする
382 Protected Shared Property DefaultTimeout() As Integer
386 Set(ByVal value As Integer)
387 Const TimeoutMinValue As Integer = 10000
388 Const TimeoutMaxValue As Integer = 120000
389 Const TimeoutDefaultValue As Integer = 20000
390 If value < TimeoutMinValue OrElse value > TimeoutMaxValue Then
392 timeout = TimeoutDefaultValue
401 '''通信クラスの初期化処理。タイムアウト値とプロキシを設定する
406 '''<param name="timeout">タイムアウト値(秒)</param>
407 '''<param name="proxyType">なし・指定・IEデフォルト</param>
408 '''<param name="proxyAddress">プロキシのホスト名orIPアドレス</param>
409 '''<param name="proxyPort">プロキシのポート番号</param>
410 '''<param name="proxyUser">プロキシ認証が必要な場合のユーザ名。不要なら空文字</param>
411 '''<param name="proxyPassword">プロキシ認証が必要な場合のパスワード。不要なら空文字</param>
412 Public Shared Sub InitializeConnection( _
413 ByVal timeout As Integer, _
414 ByVal proxyType As ProxyType, _
415 ByVal proxyAddress As String, _
416 ByVal proxyPort As Integer, _
417 ByVal proxyUser As String, _
418 ByVal proxyPassword As String)
420 ServicePointManager.Expect100Continue = False
421 DefaultTimeout = timeout * 1000 's -> ms
422 Select Case proxyType
425 Case proxyType.Specified
426 proxy = New WebProxy("http://" + proxyAddress + ":" + proxyPort.ToString)
427 If Not String.IsNullOrEmpty(proxyUser) OrElse Not String.IsNullOrEmpty(proxyPassword) Then
428 proxy.Credentials = New NetworkCredential(proxyUser, proxyPassword)
431 'IE設定(システム設定)はデフォルト値なので処理しない
433 proxyKind = proxyType