1 #Region "Microsoft.VisualBasic::30d8ecee757f177cabcb218d0be052d8, Microsoft.VisualBasic.Core\Extensions\WebServices\HttpGet.vb"
2
3     ' Author:
4     
5     '       asuka (amethyst.asuka@gcmodeller.org)
6     '       xie (genetics@smrucc.org)
7     '       xieguigang (xie.guigang@live.com)
8     
9     ' Copyright (c) 2018 GPL3 Licensed
10     
11     
12     ' GNU GENERAL PUBLIC LICENSE (GPL3)
13     
14     
15     ' This program is free software: you can redistribute it and/or modify
16     ' it under the terms of the GNU General Public License as published by
17     ' the Free Software Foundation, either version 3 of the License, or
18     ' (at your option) any later version.
19     
20     ' This program is distributed in the hope that it will be useful,
21     ' but WITHOUT ANY WARRANTY; without even the implied warranty of
22     ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     ' GNU General Public License for more details.
24     
25     ' You should have received a copy of the GNU General Public License
26     ' along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28
29
30     ' /********************************************************************************/
31
32     ' Summaries:
33
34     Module HttpGet
35     
36     '     Function: [GET], __get, __httpRequest, Get_PageContent, LogException
37     
38     ' /********************************************************************************/
39
40 #End Region
41
42 Imports System.IO
43 Imports System.Net
44 Imports System.Runtime.CompilerServices
45 Imports System.Text
46 Imports Microsoft.VisualBasic.CommandLine.Reflection
47 Imports Microsoft.VisualBasic.Language
48 Imports Microsoft.VisualBasic.Net.Http
49 Imports Microsoft.VisualBasic.Scripting.MetaData
50 Imports Microsoft.VisualBasic.Text.HtmlParser
51
52 ''' <summary>
53 ''' Tools for http get
54 ''' </summary>
55 Public Module HttpGet
56
57 #If FRAMEWORD_CORE Then
58     ''' <summary>
59     ''' Get the html page content from a website request or a html file on the local filesystem.
60     ''' (同时支持http位置或者本地文件,失败或者错误会返回空字符串)
61     ''' </summary>
62     ''' <param name="url">web http request url or a file path handle</param>
63     ''' <param name="retry">发生错误的时候的重试的次数</param>
64     ''' <returns>失败或者错误会返回空字符串</returns>
65     ''' <remarks>这个工具只适合于文本数据的传输操作</remarks>
66     <ExportAPI("Webpage.Request"Info:="Get the html page content from a website request Or a html file on the local filesystem.")>
67     <Extension> Public Function [GET](url As String,
68                                       <Parameter("Request.TimeOut")>
69                                       Optional retry As UInt16 = 0,
70                                       <Parameter("FileSystem.Works?""Is this a local html document on your filesystem?")>
71                                       Optional isFileUrl As Boolean = False,
72                                       Optional headers As Dictionary(Of StringString) = Nothing,
73                                       Optional proxy As String = Nothing,
74                                       Optional doNotRetry404 As Boolean = True,
75                                       Optional UA$ = UserAgent.GoogleChrome,
76                                       Optional refer$ = NothingAs String
77 #Else
78     ''' <summary>
79     ''' Get the html page content from a website request or a html file on the local filesystem.
80     ''' </summary>
81     ''' <param name="url">web http request url or a file path handle</param>
82     ''' <param name="RequestTimeOut">发生错误的时候的重试的次数</param>
83     ''' <returns></returns>
84     ''' <remarks></remarks>
85     '''
86     <Extension> Public Function Get_PageContent(url As StringOptional RequestTimeOut As UInteger = 20, Optional FileSystemUrl As Boolean = FalseAs String
87 #End If
88         ' Call $"Request data from: {If(isFileUrl, url.ToFileURL, url)}".__DEBUG_ECHO
89         Call $"GET {If(isFileUrl, url.ToFileURL, url)}".__DEBUG_ECHO
90
91         If FileIO.FileSystem.FileExists(url) Then
92             Call "[Job DONE!]".__DEBUG_ECHO
93             Return FileIO.FileSystem.ReadAllText(url)
94         Else
95             If isFileUrl Then
96                 Call $"URL {url.ToFileURL} can not solved on your filesystem!".Warning
97                 Return ""
98             End If
99         End If
100
101         If Not refer.StringEmpty Then
102             If headers Is Nothing Then
103                 headers = New Dictionary(Of StringString)
104             End If
105
106             headers(NameOf(refer)) = refer
107         End If
108
109         Return url.__httpRequest(retry, headers, proxy, doNotRetry404, UA)
110     End Function
111
112     <Extension>
113     Private Function __httpRequest(url$, retries%, headers As Dictionary(Of StringString), proxy$, DoNotRetry404 As Boolean, UA$) As String
114         Dim retryTime As Integer = 0
115
116         If String.IsNullOrEmpty(proxy) Then
117             proxy = WebServiceUtils.Proxy
118         End If
119
120         Try
121 RETRY:      Return __get(url, headers, proxy, UA)
122         Catch ex As Exception When InStr(ex.Message, "(404) Not Found") > 0 AndAlso DoNotRetry404
123             Return LogException(url, New Exception(url, ex))
124
125         Catch ex As Exception When retryTime < retries
126
127             retryTime += 1
128
129             Call "Data download error, retry connect to the server!".PrintException
130             GoTo RETRY
131
132         Catch ex As Exception
133             ex = New Exception(url, ex)
134             ex.PrintException
135
136             Return LogException(url, ex)
137         End Try
138     End Function
139
140     Private Function LogException(url As String, ex As Exception) As String
141         Dim exMessage As String = String.Format("Unable to get the http request!" & vbCrLf &
142                                                 "  Url:=[{0}]" & vbCrLf &
143                                                 "  EXCEPTION ===>" & vbCrLf & ex.ToString, url)
144         Call App.LogException(exMessage, NameOf([GET]) & "::HTTP_REQUEST_EXCEPTION")
145         Return ""
146     End Function
147
148     Const doctorcomError$ = "Please login your Campus Broadband Network Client at first!"
149
150     ''' <summary>
151     ''' Request timeout unit in seconds.
152     ''' </summary>
153     ''' <returns></returns>
154     Public Property HttpRequestTimeOut As Double
155
156     Private Function __get(url$, headers As Dictionary(Of StringString), proxy$, UA$) As String
157         Dim timer As Stopwatch = Stopwatch.StartNew
158         Dim webRequest As HttpWebRequest = HttpWebRequest.Create(url)
159
160         webRequest.Headers.Add("Accept-Language""en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3")
161         webRequest.UserAgent = If(UA = UserAgent.GoogleChrome, DefaultUA, UA)
162
163         If HttpRequestTimeOut > 0 Then
164             webRequest.Timeout = 1000 * HttpRequestTimeOut
165         End If
166
167         If Not headers.IsNullOrEmpty Then
168             For Each x In headers
169                 webRequest.Headers(x.Key) = x.Value
170             Next
171         End If
172         If Not String.IsNullOrEmpty(proxy) Then
173             Call webRequest.SetProxy(proxy)
174         End If
175
176         Using respStream As Stream = webRequest.GetResponse.GetResponseStream,
177             reader As New StreamReader(respStream)
178
179             Dim htmlBuilder As New StringBuilder
180             Dim line As Value(Of String) = ""
181
182             Do While Not (line = reader.ReadLine) Is Nothing
183                 htmlBuilder.AppendLine(line)
184             Loop
185
186             Dim html As String = htmlBuilder.ToString
187             Dim title As String = html.HTMLTitle
188
189             ' 判断是否是由于还没有登陆校园网客户端而导致的错误
190             If InStr(html, "http://www.doctorcom.com", CompareMethod.Text) > 0 Then
191                 Call doctorcomError.PrintException
192                 Return ""
193             End If
194
195             Call $"[{title}  {url}] --> sizeOf:={Len(html)} chars; response_time:={timer.ElapsedMilliseconds} ms.".__DEBUG_ECHO
196 #If DEBUG Then
197             Call html.SaveTo($"{App.AppSystemTemp}/{App.PID}/{url.NormalizePathString}.html")
198 #End If
199             Return html
200         End Using
201     End Function
202 End Module