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 Return res.StatusCode
179 '''HTTPの応答を処理します。応答ボディデータが不要な用途向け。
182 '''リダイレクト応答の場合(AllowAutoRedirect=Falseの場合のみ)は、headerInfoインスタンスがあればLocationを追加してリダイレクト先を返却
183 '''WebExceptionはハンドルしていないので、呼び出し元でキャッチすること
185 '''<param name="webRequest">HTTP通信リクエストオブジェクト</param>
186 '''<param name="headerInfo">[IN/OUT]HTTP応答のヘッダ情報。ヘッダ名をキーにして空データのコレクションを渡すことで、該当ヘッダの値をデータに設定して戻す</param>
187 '''<param name="withCookie">通信にcookieを使用する</param>
188 '''<returns>HTTP応答のステータスコード</returns>
189 Protected Function GetResponse(ByVal webRequest As HttpWebRequest, _
190 ByVal headerInfo As Dictionary(Of String, String), _
191 ByVal withCookie As Boolean _
194 Using webRes As HttpWebResponse = CType(webRequest.GetResponse(), HttpWebResponse)
195 Dim statusCode As HttpStatusCode = webRes.StatusCode
197 If withCookie Then SaveCookie(webRes.Cookies)
198 'リダイレクト応答の場合は、リダイレクト先を設定
199 GetHeaderInfo(webRes, headerInfo)
202 Catch ex As WebException
203 If ex.Status = WebExceptionStatus.ProtocolError Then
204 Dim res As HttpWebResponse = DirectCast(ex.Response, HttpWebResponse)
205 Return res.StatusCode
212 '''HTTPの応答を処理し、応答ボディデータをBitmapとして返却します
215 '''リダイレクト応答の場合(AllowAutoRedirect=Falseの場合のみ)は、headerInfoインスタンスがあればLocationを追加してリダイレクト先を返却
216 '''WebExceptionはハンドルしていないので、呼び出し元でキャッチすること
218 '''<param name="webRequest">HTTP通信リクエストオブジェクト</param>
219 '''<param name="contentText">[OUT]HTTP応答のボディデータを書き込むBitmap</param>
220 '''<param name="headerInfo">[IN/OUT]HTTP応答のヘッダ情報。ヘッダ名をキーにして空データのコレクションを渡すことで、該当ヘッダの値をデータに設定して戻す</param>
221 '''<param name="withCookie">通信にcookieを使用する</param>
222 '''<returns>HTTP応答のステータスコード</returns>
223 Protected Function GetResponse(ByVal webRequest As HttpWebRequest, _
224 ByRef contentBitmap As Bitmap, _
225 ByVal headerInfo As Dictionary(Of String, String), _
226 ByVal withCookie As Boolean _
229 Using webRes As HttpWebResponse = CType(webRequest.GetResponse(), HttpWebResponse)
230 Dim statusCode As HttpStatusCode = webRes.StatusCode
232 If withCookie Then SaveCookie(webRes.Cookies)
233 'リダイレクト応答の場合は、リダイレクト先を設定
234 GetHeaderInfo(webRes, headerInfo)
235 '応答のストリームをBitmapにして戻す
236 'If webRes.ContentLength > 0 Then contentBitmap = New Bitmap(webRes.GetResponseStream)
237 contentBitmap = New Bitmap(webRes.GetResponseStream)
240 Catch ex As WebException
241 If ex.Status = WebExceptionStatus.ProtocolError Then
242 Dim res As HttpWebResponse = DirectCast(ex.Response, HttpWebResponse)
243 Return res.StatusCode
250 '''クッキーを保存。ホスト名なしのドメインの場合、ドメイン名から先頭のドットを除去して追加しないと再利用されないため
252 Private Sub SaveCookie(ByVal cookieCollection As CookieCollection)
253 For Each ck As Cookie In cookieCollection
254 If ck.Domain.StartsWith(".") Then
255 ck.Domain = ck.Domain.Substring(1, ck.Domain.Length - 1)
256 cookieContainer.Add(ck)
262 '''in/outのストリームインスタンスを受け取り、コピーして返却
264 '''<param name="inStream">コピー元ストリームインスタンス。読み取り可であること</param>
265 '''<param name="outStream">コピー先ストリームインスタンス。書き込み可であること</param>
266 Private Sub CopyStream(ByVal inStream As Stream, ByVal outStream As Stream)
267 If inStream Is Nothing Then Throw New ArgumentNullException("inStream")
268 If outStream Is Nothing Then Throw New ArgumentNullException("outStream")
269 If Not inStream.CanRead Then Throw New ArgumentException("Input stream can not read.")
270 If Not outStream.CanWrite Then Throw New ArgumentException("Output stream can not write.")
271 If inStream.CanSeek AndAlso inStream.Length = 0 Then Throw New ArgumentException("Input stream do not have data.")
274 Dim buffer(1024) As Byte
275 Dim i As Integer = buffer.Length
276 i = inStream.Read(buffer, 0, i)
277 If i = 0 Then Exit Do
278 outStream.Write(buffer, 0, i)
283 '''headerInfoのキー情報で指定されたHTTPヘッダ情報を取得・格納する。redirect応答時はLocationヘッダの内容を追記する
285 '''<param name="webResponse">HTTP応答</param>
286 '''<param name="headerInfo">[IN/OUT]キーにヘッダ名を指定したデータ空のコレクション。取得した値をデータにセットして戻す</param>
287 Private Sub GetHeaderInfo(ByVal webResponse As HttpWebResponse, _
288 ByVal headerInfo As Dictionary(Of String, String))
290 If headerInfo Is Nothing Then Exit Sub
292 If headerInfo.Count > 0 Then
293 Dim keys(headerInfo.Count - 1) As String
294 headerInfo.Keys.CopyTo(keys, 0)
295 For Each key As String In keys
296 If Array.IndexOf(webResponse.Headers.AllKeys, key) > -1 Then
297 headerInfo.Item(key) = webResponse.Headers.Item(key)
299 headerInfo.Item(key) = ""
304 Dim statusCode As HttpStatusCode = webResponse.StatusCode
305 If statusCode = HttpStatusCode.MovedPermanently OrElse _
306 statusCode = HttpStatusCode.Found OrElse _
307 statusCode = HttpStatusCode.SeeOther OrElse _
308 statusCode = HttpStatusCode.TemporaryRedirect Then
309 If headerInfo.ContainsKey("Location") Then
310 headerInfo.Item("Location") = webResponse.Headers.Item("Location")
312 headerInfo.Add("Location", webResponse.Headers.Item("Location"))
318 '''クエリコレクションをkey=value形式の文字列に構成して戻す
320 '''<param name="param">クエリ、またはポストデータとなるkey-valueコレクション</param>
321 Protected Function CreateQueryString(ByVal param As IDictionary(Of String, String)) As String
322 If param Is Nothing OrElse param.Count = 0 Then Return String.Empty
324 Dim query As New StringBuilder
325 For Each key As String In param.Keys
326 query.AppendFormat("{0}={1}&", UrlEncode(key), UrlEncode(param(key)))
328 Return query.ToString(0, query.Length - 1)
332 '''クエリ形式(key1=value1&key2=value2&...)の文字列をkey-valueコレクションに詰め直し
334 '''<param name="queryString">クエリ文字列</param>
335 '''<returns>key-valueのコレクション</returns>
336 Protected Function ParseQueryString(ByVal queryString As String) As NameValueCollection
337 Dim query As New NameValueCollection
338 Dim parts() As String = queryString.Split("&"c)
339 For Each part As String In parts
340 Dim index As Integer = part.IndexOf("="c)
342 query.Add(Uri.UnescapeDataString(part), "")
344 query.Add(Uri.UnescapeDataString(part.Substring(0, index)), Uri.UnescapeDataString(part.Substring(index + 1)))
351 '''2バイト文字も考慮したUrlエンコード
353 '''<param name="str">エンコードする文字列</param>
354 '''<returns>エンコード結果文字列</returns>
355 Protected Function UrlEncode(ByVal stringToEncode As String) As String
356 Const UnreservedChars As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~"
357 Dim sb As New StringBuilder
358 Dim bytes As Byte() = Encoding.UTF8.GetBytes(stringToEncode)
360 For Each b As Byte In bytes
361 If UnreservedChars.IndexOf(Chr(b)) <> -1 Then
364 sb.AppendFormat("%{0:X2}", b)
370 #Region "DefaultTimeout"
374 Private Shared timeout As Integer = 20000
377 '''通信タイムアウト時間(ms)。10~120秒の範囲で指定。範囲外は20秒とする
379 Protected Shared Property DefaultTimeout() As Integer
383 Set(ByVal value As Integer)
384 Const TimeoutMinValue As Integer = 10000
385 Const TimeoutMaxValue As Integer = 120000
386 Const TimeoutDefaultValue As Integer = 20000
387 If value < TimeoutMinValue OrElse value > TimeoutMaxValue Then
389 timeout = TimeoutDefaultValue
398 '''通信クラスの初期化処理。タイムアウト値とプロキシを設定する
403 '''<param name="timeout">タイムアウト値(秒)</param>
404 '''<param name="proxyType">なし・指定・IEデフォルト</param>
405 '''<param name="proxyAddress">プロキシのホスト名orIPアドレス</param>
406 '''<param name="proxyPort">プロキシのポート番号</param>
407 '''<param name="proxyUser">プロキシ認証が必要な場合のユーザ名。不要なら空文字</param>
408 '''<param name="proxyPassword">プロキシ認証が必要な場合のパスワード。不要なら空文字</param>
409 Public Shared Sub InitializeConnection( _
410 ByVal timeout As Integer, _
411 ByVal proxyType As ProxyType, _
412 ByVal proxyAddress As String, _
413 ByVal proxyPort As Integer, _
414 ByVal proxyUser As String, _
415 ByVal proxyPassword As String)
417 ServicePointManager.Expect100Continue = False
418 DefaultTimeout = timeout * 1000 's -> ms
419 Select Case proxyType
422 Case proxyType.Specified
423 proxy = New WebProxy("http://" + proxyAddress + ":" + proxyPort.ToString)
424 If Not String.IsNullOrEmpty(proxyUser) OrElse Not String.IsNullOrEmpty(proxyPassword) Then
425 proxy.Credentials = New NetworkCredential(proxyUser, proxyPassword)
428 'IE設定(システム設定)はデフォルト値なので処理しない
430 proxyType = proxyType