-
Notifications
You must be signed in to change notification settings - Fork 0
/
HttpRequest.vb
250 lines (227 loc) · 9.68 KB
/
HttpRequest.vb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
Imports System.IO
Imports System.Net.Sockets
Imports System.Text
Partial Public Class Plugin
Private Class HttpRequest
Public Version As String = ""
Public Url As String = ""
Public ReadOnly UrlParams As New Dictionary(Of String, String)(StringComparer.OrdinalIgnoreCase)
Public Method As String = ""
Public ReadOnly Headers As New Dictionary(Of String, String)(StringComparer.OrdinalIgnoreCase)
Public SoapService As String
Public SoapAction As String
Public SoapOutParam() As String
Public Socket As TcpClient
Private chunkedStream As ChunkedStream
Private ReadOnly socketStream As NetworkStream
'Private httpResponse As HttpResponse
Public Sub New(socket As TcpClient)
Me.Socket = socket
Me.socketStream = socket.GetStream()
End Sub
Public Sub SetSoap(soapAction As String, soapService As String, soapOutParam As String())
Me.SoapAction = soapAction
Me.SoapService = soapService
Me.SoapOutParam = soapOutParam
End Sub
Public Sub ParseHeaders()
Dim text As New StringBuilder(128)
Dim isFirstLine As Boolean = True
Do
Dim b As Integer = socketStream.ReadByte()
'' changed to included end of stream error
If b = -1 Then
Throw New HttpException(400, "Bad header")
ElseIf b = 13 Then
' ignore
ElseIf b = 10 Then
Dim line As String = text.ToString()
If line.Length = 0 Then Exit Do
text.Length = 0
If isFirstLine Then
Dim values As String() = line.Split(New Char() {" "c}, 2, StringSplitOptions.RemoveEmptyEntries)
Method = values(0).ToUpper()
Dim index As Integer = values(1).LastIndexOf(" "c)
Version = values(1).Substring(index + 1)
values = Uri.UnescapeDataString(values(1).Substring(0, index)).Split(New Char() {"?"c}, 2, StringSplitOptions.RemoveEmptyEntries)
Url = values(0).ToLower()
If values.Length = 2 Then
For Each parameter As String In values(1).Split(New Char() {"&"c}, StringSplitOptions.RemoveEmptyEntries)
Dim keyValue As String() = parameter.Split(New Char() {"="c}, 2, StringSplitOptions.RemoveEmptyEntries)
UrlParams(keyValue(0)) = If((keyValue.Length <> 2), "", keyValue(1))
Next parameter
End If
isFirstLine = False
Else
Dim keyValue As String() = line.Split(New Char() {":"c}, 2, StringSplitOptions.RemoveEmptyEntries)
Headers(keyValue(0).Trim()) = If(keyValue.Length <= 1, "", keyValue(1).Trim())
End If
Else
text.Append(ChrW(b))
End If
Loop
Dim transferEncoding As String
If Headers.TryGetValue("Transfer-Encoding", transferEncoding) AndAlso String.Compare(transferEncoding.Trim(""""c), "chunked", StringComparison.OrdinalIgnoreCase) = 0 Then
LogInformation("httprequest", "chunked stream")
chunkedStream = New ChunkedStream(socketStream, True)
End If
End Sub
Public Function GetLength() As Integer
Return Integer.Parse(Headers("Content-Length"))
End Function
Public ReadOnly Property Stream() As Stream
Get
Return If(chunkedStream Is Nothing, DirectCast(socketStream, Stream), DirectCast(chunkedStream, Stream))
End Get
End Property
Public Sub Close()
Stream.Close()
'If httpResponse Is Nothing Then
' Stream.Close()
'Else
' httpResponse.CloseStream()
'End If
Socket.Close()
End Sub
Public Function GetContent() As IO.MemoryStream
If chunkedStream Is Nothing Then
Dim buffer As Byte() = New Byte(GetLength() - 1) {}
Dim readCount As Integer
Dim offset As Integer = 0
Do While offset < buffer.Length
readCount = socketStream.Read(buffer, offset, buffer.Length - offset)
If readCount <= 0 Then
Exit Do
End If
offset += readCount
Loop
Return New IO.MemoryStream(buffer, 0, buffer.Length)
Else
Dim sourceStream As New IO.MemoryStream
chunkedStream.CopyTo(sourceStream)
sourceStream.Flush()
sourceStream.Position = 0
Return sourceStream
End If
End Function
Public ReadOnly Property Response() As HttpResponse
Get
Return New HttpResponse(Me, socketStream)
'If httpResponse Is Nothing Then
' Return New HttpResponse(Me, socketStream)
'End If
'Return httpResponse
End Get
End Property
End Class ' HttpRequest
Private NotInheritable Class ChunkedStream
Inherits Stream
Private ReadOnly socketStream As NetworkStream
Private chunkSize As Integer
Private ReadOnly [readonly] As Boolean
Public Sub New(socketStream As NetworkStream, canRead As Boolean)
Me.socketStream = socketStream
Me.[readonly] = canRead
End Sub
Public Overrides ReadOnly Property CanRead As Boolean
Get
Return [readonly]
End Get
End Property
Public Overrides ReadOnly Property CanSeek As Boolean
Get
Return False
End Get
End Property
Public Overrides ReadOnly Property CanWrite As Boolean
Get
Return Not [readonly]
End Get
End Property
Public Overrides ReadOnly Property CanTimeout As Boolean
Get
Return socketStream.CanTimeout
End Get
End Property
Public Overrides Sub Flush()
socketStream.Flush()
End Sub
Public Overrides ReadOnly Property Length As Long
Get
Throw New NotSupportedException
End Get
End Property
Public Overrides Property Position As Long
Get
Throw New NotSupportedException
End Get
Set(value As Long)
Throw New NotSupportedException
End Set
End Property
Public Overrides Function Read(buffer() As Byte, offset As Integer, count As Integer) As Integer
If Not CanRead Then
Throw New NotSupportedException
End If
If chunkSize > 0 Then
Dim minCount As Integer = Math.Min(count, chunkSize)
Dim readCount As Integer = socketStream.Read(buffer, offset, minCount)
chunkSize -= readCount
If chunkSize = 0 Then
socketStream.ReadByte()
socketStream.ReadByte()
End If
Return readCount
Else
Dim text As New StringBuilder(128)
Do
Dim b As Integer = socketStream.ReadByte()
'' changed to included end of stream error
If b = -1 Then
Throw New HttpException(400, "Bad chunk header")
ElseIf b = 13 Then
' ignore
ElseIf b = 10 Then
Dim line As String = text.ToString()
Dim index As Integer = line.IndexOf(";"c)
If index > 0 Then
line = line.Substring(0, index).Trim()
End If
chunkSize = Integer.Parse(line, Globalization.NumberStyles.HexNumber)
If chunkSize <= 0 Then
chunkSize = 0
Return 0
Else
Return Read(buffer, offset, count)
End If
Else
text.Append(ChrW(b))
End If
Loop
'Throw New HttpException(400, "Bad chunk header")
End If
End Function
Public Overrides Function Seek(offset As Long, origin As SeekOrigin) As Long
Throw New NotSupportedException
End Function
Public Overrides Sub SetLength(value As Long)
Throw New NotSupportedException
End Sub
Public Overrides Sub Write(buffer() As Byte, offset As Integer, count As Integer)
If CanRead Then
Throw New NotSupportedException
End If
Dim header() As Byte = Encoding.ASCII.GetBytes(String.Format("{0:X}" & ControlChars.CrLf, count))
socketStream.Write(header, 0, header.Length)
socketStream.Write(buffer, offset, count)
socketStream.Write(New Byte() {13, 10}, 0, 2)
socketStream.Flush()
End Sub
Public Overrides Sub Close()
If Not CanRead Then
socketStream.Write(New Byte() {0, 13, 10}, 0, 3)
End If
socketStream.Close()
End Sub
End Class ' ChunkedStream
End Class