http.bi 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. ' http.bi is part of Bliss (track editor for Stunts)
  2. ' Copyright (C) 2016-2018 Lucas Pedrosa
  3. ' Bliss is free software: you can redistribute it and/or modify
  4. ' it under the terms of the GNU General Public License as published by
  5. ' the Free Software Foundation, version 3 of the License.
  6. ' This program is distributed in the hope that it will be useful,
  7. ' but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. ' GNU General Public License for more details.
  10. ' You should have received a copy of the GNU General Public License
  11. ' along with this program. If not, see <http://www.gnu.org/licenses/>.
  12. #ifdef __FB_WIN32__
  13. #include "windows.bi"
  14. #include "win/windef.bi"
  15. #include "win/winsock2.bi"
  16. #ifndef opensocket
  17. #define opensocket socket
  18. #endif
  19. #else
  20. #include "crt/unistd.bi"
  21. #include "crt/netinet/in.bi"
  22. #include "crt/sys/select.bi"
  23. #include "crt/netdb.bi"
  24. #include "crt/arpa/inet.bi"
  25. #endif
  26. #ifndef TCP_NODELAY
  27. #define TCP_NODELAY &H01
  28. #endif
  29. Declare Sub HTTP_Start
  30. Declare Sub HTTP_End
  31. Declare Function HTTP_StartServer(ByVal port As UShort, max_connections As Integer) As Byte
  32. Declare Function HTTP_GetClient As Long
  33. Declare Function HTTP_Connect(address As String, port As UShort) As Byte
  34. Declare Function HTTP_BuildGet(host As String, path As String, mimetype As String = "") As String
  35. Declare Function HTTP_BuildHead(host As String, path As String, mimetype As String = "") As String
  36. Declare Function HTTP_BuildPost(host As String, path As String, query As String, refer As Byte) As String
  37. Declare Function HTTP_ReadyToGet As Byte
  38. Declare Function HTTP_ReadyToPut As Byte
  39. Declare Function HTTP_GetData(ByRef dbuffer As Any Ptr) As Long
  40. Declare Function HTTP_PutData(ByVal dbuffer As Any Ptr, ByVal datasize As Long) As Long
  41. Dim Shared HTTP_Socket As Long, HTTP_addr As sockaddr_in
  42. Dim Shared As fd_set HTTP_writefds, HTTP_readfds, HTTP_readfd
  43. Dim Shared HTTP_timeout As timeval
  44. Function HTTP_BuildGet(host As String, path As String, mimetype As String = "") As String
  45. Dim s As String
  46. s = "GET " + path + " HTTP/1.1" + Chr(13, 10)
  47. s += "Host: " + host + Chr(13, 10)
  48. If Len(mimetype) Then s += "mime: " + mimetype + Chr(13, 10)
  49. s += Chr(13, 10)
  50. Return s
  51. End Function
  52. Function HTTP_BuildHead(host As String, path As String, mimetype As String = "") As String
  53. Dim s As String
  54. s = "HEAD " + path + " HTTP/1.1" + Chr(13, 10)
  55. s += "Host: " + host + Chr(13, 10)
  56. If Len(mimetype) Then s += "mime: " + mimetype + Chr(13, 10)
  57. s += Chr(13, 10)
  58. Return s
  59. End Function
  60. Function HTTP_BuildPost(host As String, path As String, query As String, refer As Byte) As String
  61. Dim s As String
  62. s = "POST " + path + " HTTP/1.1" + Chr(13, 10)
  63. s += "Host: " + host + Chr(13, 10)
  64. If refer Then s += "Referer: http://" + host + path + "?" + Chr(13, 10)
  65. s += "Content-type: application/x-www-form-urlencoded" + Chr(13, 10)
  66. s += "Content-length: " + Str(Len(query)) + Chr(13, 10)
  67. s += "Connection: close" + Chr(13, 10, 13, 10)
  68. s += query
  69. Return s
  70. End Function
  71. Function HTTP_Connect(address As String, port As UShort) As Byte
  72. HTTP_Start
  73. HTTP_Socket = opensocket(AF_INET, SOCK_STREAM, 0)
  74. If HTTP_Socket = -1 Then Return -1
  75. Dim he As hostent Ptr
  76. he = gethostbyname(StrPtr(address))
  77. If he = 0 Then Return -2
  78. HTTP_addr.sin_family = AF_INET
  79. HTTP_addr.sin_port = htons(port)
  80. HTTP_addr.sin_addr = *CPtr(in_addr Ptr, he->h_addr_list[0])
  81. If connect(HTTP_Socket, CPtr(sockaddr Ptr, @HTTP_addr), SizeOf(sockaddr)) < 0 Then
  82. Return -3
  83. End if
  84. Return 0
  85. End Function
  86. Function HTTP_Download(address As String, ByRef buffer As UByte Ptr, isawebpage As Byte = 0) As Long
  87. Dim request As String, n As Short
  88. Dim As String host, path, mime
  89. Dim t As Double, bytes As Long, newbuffer As UByte Ptr
  90. Dim header As ZString Ptr
  91. If isawebpage Then mime = "text/html;text/plain" Else mime = ""
  92. n = InStr(address, "/")
  93. If n Then
  94. host = Left(address, n - 1)
  95. path = Mid(address, n)
  96. Else
  97. host = address
  98. path = "/"
  99. End If
  100. If HTTP_Connect(host, 80) Then Return -1 'Could not connect
  101. request = HTTP_BuildGet(host, path, mime)
  102. t = Timer
  103. Do
  104. If HTTP_ReadyToPut Then Exit Do
  105. If Timer > t + 3 Then Return -2 'Time-out 3 seconds
  106. Sleep 100
  107. Loop
  108. HTTP_PutData StrPtr(request), Len(request)
  109. t = Timer
  110. Do
  111. If HTTP_ReadyToGet Then Exit Do
  112. If Timer > t + 3 Then Return -3 'Time-out 3 seconds
  113. Sleep 100
  114. Loop
  115. bytes = HTTP_GetData(newbuffer)
  116. header = newbuffer
  117. n = InStr(*header, Chr(13, 10, 13, 10)) + 3
  118. If buffer Then Deallocate buffer : buffer = 0
  119. If bytes - n >= 1 Then
  120. buffer = Allocate(bytes - n)
  121. For i As Long = 0 To bytes - n - 1
  122. buffer[i] = newbuffer[i + n]
  123. Next i
  124. End If
  125. Deallocate newbuffer
  126. Return bytes - n
  127. End Function
  128. Sub HTTP_End
  129. If HTTP_Socket >= 1 Then closesocket(HTTP_Socket)
  130. #ifdef __FB_WIN32__
  131. WSACleanup()
  132. #endif
  133. End Sub
  134. Function HTTP_GetData(ByRef dbuffer As Any Ptr) As Long
  135. Static chunk(8191) As UByte
  136. If HTTP_Socket < 0 Then Return -1
  137. Dim dsize As Long, bytes As Long, pwrite As UByte Ptr, i As Long
  138. If dbuffer Then Deallocate dbuffer : dbuffer = 0
  139. Do
  140. bytes = recv(HTTP_Socket, @chunk(0), 8192, 0)
  141. If bytes = 0 Then
  142. If dsize = 0 Then Return -1
  143. Exit Do
  144. End If
  145. If bytes < 0 Then Return -1
  146. dbuffer = Reallocate(dbuffer, dsize + bytes)
  147. pwrite = dbuffer + dsize
  148. For i = 0 To bytes - 1
  149. pwrite[i] = chunk(i)
  150. Next i
  151. dsize += bytes
  152. Sleep 20
  153. For i = 1 To 100
  154. If HTTP_ReadyToGet Then Exit For
  155. Sleep 10
  156. Next i
  157. Loop Until i > 100
  158. Return dsize
  159. End Function
  160. Function HTTP_PutData(ByVal dbuffer As Any Ptr, ByVal datasize As Long) As Long
  161. If HTTP_Socket < 0 Or dbuffer = 0 Or datasize < 1 Then Return -1
  162. Dim size As Long, dsize As Integer, bytes As Long
  163. dsize = datasize
  164. While (size < datasize)
  165. bytes = send(HTTP_Socket, dbuffer, dsize, 0)
  166. If bytes < 0 Then Return -1
  167. dbuffer += bytes
  168. dsize -= bytes
  169. size += bytes
  170. WEnd
  171. Return size
  172. End Function
  173. Function HTTP_ReadyToGet As Byte
  174. If HTTP_Socket < 0 Then Return -1
  175. FD_ZERO(@HTTP_readfds)
  176. FD_SET_(HTTP_Socket, @HTTP_readfds)
  177. If select_(HTTP_Socket + 1, @HTTP_readfds, 0, 0, @HTTP_timeout) = -1 Then Return -1
  178. Return IIf(FD_ISSET(HTTP_Socket, @HTTP_readfds), -1, 0)
  179. End Function
  180. Function HTTP_ReadyToPut As Byte
  181. If HTTP_Socket < 0 Then Return -1
  182. FD_ZERO(@HTTP_writefds)
  183. FD_SET_(HTTP_Socket, @HTTP_writefds)
  184. If select_(HTTP_Socket + 1, 0, @HTTP_writefds, 0, @HTTP_timeout) = -1 Then Return -1
  185. Return IIf(FD_ISSET(HTTP_Socket, @HTTP_writefds), -1, 0)
  186. End Function
  187. Sub HTTP_Start
  188. Static already_initialised As Byte = 0
  189. #ifdef __FB_WIN32__
  190. If Not already_initialised Then
  191. Dim wdata As WSAData
  192. WSAStartup(WINSOCK_VERSION, @wdata)
  193. already_initialised = -1
  194. End If
  195. #endif
  196. End Sub
  197. Function HTTP_GetClient As Long
  198. Dim ip As Long
  199. FD_ZERO(@HTTP_readfd)
  200. FD_SET_(HTTP_Socket, @HTTP_readfd)
  201. If select_(HTTP_Socket + 1, @HTTP_readfd, 0, 0, @HTTP_timeout) = -1 _
  202. Then Return 0
  203. If FD_ISSET(HTTP_Socket, @HTTP_readfd) Then
  204. ip = accept(HTTP_Socket, 0, 0)
  205. If ip = -1 Then Return 0
  206. Return ip
  207. Else
  208. Return 0
  209. End If
  210. End Function