1 #Region "Microsoft.VisualBasic::ebff84e767340583f68aa576db37f8ad, 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     '     Properties: HttpRequestTimeOut
37     
38     '     Function: [GET], __get, __httpRequest, Get_PageContent, LogException
39     
40     ' /********************************************************************************/
41
42 #End Region
43
44 Imports System.IO
45 Imports System.Net
46 Imports System.Runtime.CompilerServices
47 Imports System.Text
48 Imports Microsoft.VisualBasic.CommandLine.Reflection
49 Imports Microsoft.VisualBasic.Language
50 Imports Microsoft.VisualBasic.Net.Http
51 Imports Microsoft.VisualBasic.Scripting.MetaData
52 Imports Microsoft.VisualBasic.Text.HtmlParser
53
54 ''' <summary>
55 ''' Tools for http get
56 ''' </summary>
57 Public Module HttpGet
58
59 #If FRAMEWORD_CORE Then
60     ''' <summary>
61     ''' Get the html page content from a website request or a html file on the local filesystem.
62     ''' (同时支持http位置或者本地文件,失败或者错误会返回空字符串)
63     ''' </summary>
64     ''' <param name="url">web http request url or a file path handle</param>
65     ''' <param name="retry">发生错误的时候的重试的次数</param>
66     ''' <returns>失败或者错误会返回空字符串</returns>
67     ''' <remarks>这个工具只适合于文本数据的传输操作</remarks>
68     <ExportAPI("Webpage.Request"Info:="Get the html page content from a website request Or a html file on the local filesystem.")>
69     <Extension> Public Function [GET](url As String,
70                                       <Parameter("Request.TimeOut")>
71                                       Optional retry As UInt16 = 0,
72                                       <Parameter("FileSystem.Works?""Is this a local html document on your filesystem?")>
73                                       Optional isFileUrl As Boolean = False,
74                                       Optional headers As Dictionary(Of StringString) = Nothing,
75                                       Optional proxy As String = Nothing,
76                                       Optional doNotRetry404 As Boolean = True,
77                                       Optional UA$ = UserAgent.GoogleChrome,
78                                       Optional refer$ = NothingAs String
79 #Else
80     ''' <summary>
81     ''' Get the html page content from a website request or a html file on the local filesystem.
82     ''' </summary>
83     ''' <param name="url">web http request url or a file path handle</param>
84     ''' <param name="RequestTimeOut">发生错误的时候的重试的次数</param>
85     ''' <returns></returns>
86     ''' <remarks></remarks>
87     '''     <Extension> Public Function Get_PageContent(url As StringOptional RequestTimeOut As UInteger = 20, Optional FileSystemUrl As Boolean = FalseAs String
88 #End If
89         ' Call $"Request data from: {If(isFileUrl, url.ToFileURL, url)}".__DEBUG_ECHO
90         Call $"GET {If(isFileUrl, url.ToFileURL, url)}".__DEBUG_ECHO
91
92         If FileIO.FileSystem.FileExists(url) Then
93             Call "[Job DONE!]".__DEBUG_ECHO
94             Return FileIO.FileSystem.ReadAllText(url)
95         Else
96             If isFileUrl Then
97                 Call $"URL {url.ToFileURL} can not solved on your filesystem!".Warning
98                 Return ""
99             End If
100         End If
101
102         If Not refer.StringEmpty Then
103             If headers Is Nothing Then
104                 headers = New Dictionary(Of StringString)
105             End If
106
107             headers(NameOf(refer)) = refer
108         End If
109
110         Return url.__httpRequest(retry, headers, proxy, doNotRetry404, UA)
111     End Function
112
113     <Extension>
114     Private Function __httpRequest(url$, retries%, headers As Dictionary(Of StringString), proxy$, DoNotRetry404 As Boolean, UA$) As String
115         Dim retryTime As Integer = 0
116
117         If String.IsNullOrEmpty(proxy) Then
118             proxy = WebServiceUtils.Proxy
119         End If
120
121         Try
122 RETRY:      Return __get(url, headers, proxy, UA)
123         Catch ex As Exception When InStr(ex.Message, "(404) Not Found") > 0 AndAlso DoNotRetry404
124             Return LogException(url, New Exception(url, ex))
125
126         Catch ex As Exception When retryTime < retries
127
128             retryTime += 1
129
130             Call "Data download error, retry connect to the server!".PrintException
131             GoTo RETRY
132
133         Catch ex As Exception
134             ex = New Exception(url, ex)
135             ex.PrintException
136
137             Return LogException(url, ex)
138         End Try
139     End Function
140
141     Private Function LogException(url As String, ex As Exception) As String
142         Dim exMessage As String = String.Format("Unable to get the http request!" & vbCrLf &
143                                                 "  Url:=[{0}]" & vbCrLf &
144                                                 "  EXCEPTION ===>" & vbCrLf & ex.ToString, url)
145         Call App.LogException(exMessage, NameOf([GET]) & "::HTTP_REQUEST_EXCEPTION")
146         Return ""
147     End Function
148
149     Const doctorcomError$ = "Please login your Campus Broadband Network Client at first!"
150
151     ''' <summary>
152     ''' Request timeout unit in seconds.
153     ''' </summary>
154     ''' <returns></returns>
155     Public Property HttpRequestTimeOut As Double
156
157     Private Function __get(url$, headers As Dictionary(Of StringString), proxy$, UA$) As String
158         Dim timer As Stopwatch = Stopwatch.StartNew
159         Dim webRequest As HttpWebRequest = HttpWebRequest.Create(url)
160
161         webRequest.Headers.Add("Accept-Language""en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3")
162         webRequest.UserAgent = If(UA = UserAgent.GoogleChrome, DefaultUA, UA)
163
164         If HttpRequestTimeOut > 0 Then
165             webRequest.Timeout = 1000 * HttpRequestTimeOut
166         End If
167
168         If Not headers.IsNullOrEmpty Then
169             For Each x In headers
170                 webRequest.Headers(x.Key) = x.Value
171             Next
172         End If
173         If Not String.IsNullOrEmpty(proxy) Then
174             Call webRequest.SetProxy(proxy)
175         End If
176
177         Using respStream As Stream = webRequest.GetResponse.GetResponseStream,
178             reader As New StreamReader(respStream)
179
180             Dim htmlBuilder As New StringBuilder
181             Dim line As Value(Of String) = ""
182
183             Do While Not (line = reader.ReadLine) Is Nothing
184                 htmlBuilder.AppendLine(line)
185             Loop
186
187             Dim html As String = htmlBuilder.ToString
188             Dim title As String = html.HTMLTitle
189
190             ' 判断是否是由于还没有登陆校园网客户端而导致的错误
191             If InStr(html, "http://www.doctorcom.com", CompareMethod.Text) > 0 Then
192                 Call doctorcomError.PrintException
193                 Return ""
194             End If
195
196             Call $"[{title}  {url}] --> sizeOf:={Len(html)} chars; response_time:={timer.ElapsedMilliseconds} ms.".__DEBUG_ECHO
197 #If DEBUG Then
198             Call html.SaveTo($"{App.AppSystemTemp}/{App.PID}/{url.NormalizePathString}.html")
199 #End If
200             Return html
201         End Using
202     End Function
203 End Module