curlmain.bmx 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655
  1. ' Copyright (c) 2007-2022 Bruce A Henderson
  2. '
  3. ' Permission is hereby granted, free of charge, to any person obtaining a copy
  4. ' of this software and associated documentation files (the "Software"), to deal
  5. ' in the Software without restriction, including without limitation the rights
  6. ' to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. ' copies of the Software, and to permit persons to whom the Software is
  8. ' furnished to do so, subject to the following conditions:
  9. '
  10. ' The above copyright notice and this permission notice shall be included in
  11. ' all copies or substantial portions of the Software.
  12. '
  13. ' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. ' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. ' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. ' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. ' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. ' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. ' THE SOFTWARE.
  20. SuperStrict
  21. Import BRL.Map
  22. Import BRL.Stream
  23. Import BRL.LinkedList
  24. Import "common.bmx"
  25. Rem
  26. bbdoc: Sets up the program environment that libcurl needs.
  27. about: This will be run internally on the creation of the first #TCurlEasy with default values, but you can
  28. call it yourself if you need to set anything specifically.
  29. <p>
  30. The flags option is a bit pattern that tells libcurl exactly what features to init, as described below.
  31. Set the desired bits by ORing the values together. In normal operation, you must specify CURL_GLOBAL_ALL.
  32. Don't use any other value unless you are familiar with and mean to control internal operations of libcurl.
  33. </p>
  34. <p>Available options:</p>
  35. <ul>
  36. <li>CURL_GLOBAL_ALL</li>
  37. <li>CURL_GLOBAL_SSL</li>
  38. <li>CURL_GLOBAL_WIN32</li>
  39. <li>CURL_GLOBAL_NOTHING</li>
  40. </ul>
  41. End Rem
  42. Function CurlGlobalInit:Int(flags:Int)
  43. Return curl_global_init(flags)
  44. End Function
  45. Rem
  46. bbdoc: Returns a string describing a libcurl error code.
  47. End Rem
  48. Function CurlError:String(errorCode:Int)
  49. Return String.fromUTF8String(curl_easy_strerror(errorCode))
  50. End Function
  51. Type TCurlHasLists Abstract
  52. Field sLists:TSList[]
  53. Method freeLists()
  54. If sLists Then
  55. For Local i:Int = 0 Until sLists.length
  56. curl_slist_free_all(sLists[i].slist)
  57. Next
  58. sLists = Null
  59. End If
  60. End Method
  61. End Type
  62. Rem
  63. bbdoc: The libcurl easy interface.
  64. about: When using libcurl's "easy" interface you create your new session and get a #TCurlEasy handle
  65. (often referred to as an "easy handle").
  66. <p>
  67. You then set all the options you want in the upcoming transfer, the most important among them is the
  68. URL itself (you can't transfer anything without a specified URL as you may have figured out yourself).
  69. You might want to set some callbacks as well that will be called from the library when data is
  70. available etc. There are various methods to use depending on the type of option you want to set. They are,
  71. #setOptInt, #setOptLong, #setOptBytePtr, #setOptString, #setPrivate, #setProgressCallback,
  72. #setDebugCallback, #setWriteStream, #setWriteCallback, #setWriteString, #setReadStream, #setReadCallback,
  73. #setHeaderCallback, #httpPost, #httpHeader, #http200Aliases, #preQuote, #quote and #postQuote.
  74. </p>
  75. <p>
  76. When all is setup, you tell libcurl to perform the transfer using #perform. It will then do the entire
  77. operation and won't return until it is done (successfully or not).
  78. </p>
  79. <p>
  80. After the transfer has been made, you can set new options and make another transfer, or if you're done,
  81. cleanup the session by calling #cleanup. If you want persistent connections, you don't cleanup immediately,
  82. but instead run ahead and perform other transfers using the same easy handle.
  83. </p>
  84. End Rem
  85. Type TCurlEasy Extends TCurlHasLists
  86. Field easyHandlePtr:Byte Ptr
  87. ' keeps strings alive for as long as we need them...
  88. Field stringMap:TMap = New TMap
  89. ' the transfer data as a string...
  90. Field data:String
  91. Rem
  92. bbdoc:
  93. returns: A new instance of #TCurlEasy or Null if the libcurl handle could not be created.
  94. End Rem
  95. Function Create:TCurlEasy()
  96. Local this:TCurlEasy = New TCurlEasy
  97. this.easyHandlePtr = curl_easy_init()
  98. If Not this.easyHandlePtr Then
  99. Return Null
  100. End If
  101. Return this
  102. End Function
  103. Method setOpt(option:Int, parameter:Byte Ptr)
  104. If easyHandlePtr Then
  105. bmx_curl_easy_setopt_ptr(easyHandlePtr, option, parameter)
  106. End If
  107. End Method
  108. Rem
  109. bbdoc: Data that should be associated with this curl handle.
  110. about: The data can subsequently be retrieved using #getInfo with the #privateData method.
  111. libcurl itself does nothing with this data.
  112. <p>
  113. Use this instead of setopt #CURLOPT_PRIVATE
  114. </p>
  115. End Rem
  116. Method setPrivate(data:Object)
  117. If easyHandlePtr Then
  118. bmx_curl_easy_setopt_obj(easyHandlePtr, CURLOPT_PRIVATE, data)
  119. End If
  120. End Method
  121. Rem
  122. bbdoc: Sets a particular curl @option with the int @parameter.
  123. End Rem
  124. Method setOptInt:Int(option:Int, parameter:Int)
  125. If easyHandlePtr Then
  126. Return bmx_curl_easy_setopt_int(easyHandlePtr, option, parameter)
  127. End If
  128. End Method
  129. Rem
  130. bbdoc: Sets a particular curl @option with the long @parameter.
  131. End Rem
  132. Method setOptLong:Int(option:Int, parameter:Long)
  133. If easyHandlePtr Then
  134. Return bmx_curl_easy_setopt_bbint64(easyHandlePtr, option, parameter)
  135. End If
  136. End Method
  137. Rem
  138. bbdoc: Sets a particular curl @option with the byte ptr @parameter.
  139. End Rem
  140. Method setOptBytePtr:Int(option:Int, parameter:Byte Ptr)
  141. If easyHandlePtr Then
  142. Return bmx_curl_easy_setopt_ptr(easyHandlePtr, option, parameter)
  143. End If
  144. End Method
  145. Rem
  146. bbdoc: Sets a particular curl @option with the String @parameter.
  147. End Rem
  148. Method setOptString:Int(option:Int, parameter:String)
  149. If easyHandlePtr Then
  150. ' strings need to be alive for as long as libcurl needs them... so we cache them.
  151. Local s:Byte Ptr
  152. Local opt:TCurlInt = TCurlInt(stringMap.ValueForKey(String(option)))
  153. If opt Then
  154. ' done with this one... free it up.
  155. If opt.s Then
  156. MemFree(opt.s)
  157. End If
  158. Else
  159. opt = New TCurlInt
  160. opt.opt = option
  161. stringMap.insert(String(option), opt)
  162. End If
  163. If parameter Then
  164. opt.s = parameter.toUTF8String()
  165. Return bmx_curl_easy_setopt_str(easyHandlePtr, option, opt.s)
  166. Else
  167. opt.s = Null
  168. Return bmx_curl_easy_setopt_ptr(easyHandlePtr, option, Null)
  169. End If
  170. End If
  171. End Method
  172. Rem
  173. bbdoc: Perform a file transfer.
  174. returns: 0 when successful, or non-zero when an error occured.
  175. about: This method is called after all the @setOpt calls are made, and will perform the transfer as described in the options.
  176. You can do any amount of calls to #perform while using the same handle. If you intend to transfer more than one
  177. file, you are even encouraged to do so. libcurl will then attempt to re-use the same connection for the
  178. following transfers, thus making the operations faster, less CPU intense and using less network resources.<br>
  179. Just note that you will have to use @setopt between the invokes to set options for the following #perform.
  180. End Rem
  181. Method perform:Int()
  182. If easyHandlePtr Then
  183. Return curl_easy_perform(easyHandlePtr)
  184. End If
  185. End Method
  186. Rem
  187. bbdoc: End a libcurl easy session.
  188. about: This function must be the last function to call for an easy session.<br>
  189. This will effectively close all connections this handle has used and possibly has kept open until now.
  190. Don't call this method if you intend to transfer more files.<br>
  191. BlitzMax will call this method when the instance of the #TCurlEasy object is garbage collected, but you should
  192. probably call it yourself when you are done with the session. Once called, create yourself a new #TCurlEasy
  193. object when you need a new connection.
  194. End Rem
  195. Method cleanup()
  196. If easyHandlePtr Then
  197. curl_easy_cleanup(easyHandlePtr)
  198. easyHandlePtr = Null
  199. End If
  200. ' free up the slists
  201. freeLists()
  202. ' cleanup strings
  203. For Local i:TCurlInt = EachIn stringMap.values()
  204. MemFree(i.s)
  205. Next
  206. stringMap.clear()
  207. ' cleanup callbacks and related data
  208. dbData = Null
  209. dbFunction = Null
  210. wrData = Null
  211. wrFunction = Null
  212. rdData = Null
  213. rdFunction = Null
  214. hrData = Null
  215. hrFunction = Null
  216. End Method
  217. Rem
  218. bbdoc: Reset all options of a libcurl session handle.
  219. about: Re-initializes all options previously set on a specified CURL handle to the default values.
  220. This puts back the handle to the same state as it was in when it was first created.<br>
  221. It does not change the following information kept in the handle: live connections, the Session ID cache,
  222. the DNS cache, the cookies and shares.
  223. End Rem
  224. Method reset()
  225. If easyHandlePtr Then
  226. curl_easy_reset(easyHandlePtr)
  227. End If
  228. End Method
  229. Rem
  230. bbdoc: Get transfer progress information.
  231. about: This function gets called by libcurl instead of its internal equivalent with a frequent interval.
  232. While data is being transferred it will be called very frequently, and during slow periods like when
  233. nothing is being transferred it can slow down to about one call per second.
  234. The callback gets told how much data libcurl will transfer and has transferred, in number of bytes.
  235. @dltotal is the total number of bytes libcurl expects to download in this transfer.
  236. @dlnow is the number of bytes downloaded so far. @ultotal is the total number of bytes libcurl expects to
  237. upload in this transfer. @ulnow is the number of bytes uploaded so far.
  238. Unknown/unused argument values passed to the callback will be set to zero (like if you only download
  239. data, the upload size will remain 0). Returning a non-zero value from this callback will cause libcurl
  240. to abort the transfer and return #CURLE_ABORTED_BY_CALLBACK.
  241. <p>
  242. If you transfer data with the multi interface, this function will not be called during periods of idleness
  243. unless you call the appropriate libcurl function that performs transfers.
  244. </p>
  245. <p><i>Notes: </i>This is a convenience method for using setopt with #CURLOPT_XFERINFOFUNCTION and #CURLOPT_XFERINFODATA.</p>
  246. End Rem
  247. Method setProgressCallback(xferinfoFunction:Int(data:Object, dltotal:Long, dlnow:Long, ultotal:Long, ulnow:Long), data:Object = Null)
  248. If easyHandlePtr Then
  249. ' enable progress callback
  250. setOptInt(CURLOPT_NOPROGRESS, 0)
  251. ' set the callback
  252. bmx_curl_easy_setopt_ptr(easyHandlePtr, CURLOPT_XFERINFOFUNCTION, xferinfoFunction)
  253. ' set user data. Need to set it to at least Null so the callback doesn't send us a NULL pointer instead of a Null Object.
  254. bmx_curl_easy_setopt_obj(easyHandlePtr, CURLOPT_XFERINFODATA, data)
  255. End If
  256. End Method
  257. Rem
  258. bbdoc: Allows the replacement of the standard debug function used when #CURLOPT_VERBOSE is in effect.
  259. about: This callback receives debug information, as specified with the msgType argument. The function must
  260. return 0.
  261. <p>
  262. Possible msgTypes include, #CURLINFO_TEXT, #CURLINFO_HEADER_IN, #CURLINFO_HEADER_OUT, #CURLINFO_DATA_IN
  263. and #CURLINFO_DATA_OUT.
  264. </p>
  265. <p><i>Notes: </i>This is a convenience method for using setopt with #CURLOPT_DEBUGFUNCTION and #CURLOPT_DEBUGDATA.</p>
  266. End Rem
  267. Method setDebugCallback(debugFunction:Int(data:Object, msgType:Int, message:String), data:Object = Null)
  268. If easyHandlePtr Then
  269. dbFunction = debugFunction
  270. dbData = data
  271. bmx_curl_easy_setopt_ptr(easyHandlePtr, CURLOPT_DEBUGFUNCTION, dbCallback)
  272. bmx_curl_easy_setopt_obj(easyHandlePtr, CURLOPT_DEBUGDATA, Self)
  273. End If
  274. End Method
  275. ' +++++
  276. Field dbData:Object
  277. Field dbFunction:Int(data:Object, msgType:Int, message:String)
  278. Function dbCallback:Int(handle:Byte Ptr, infotype:Int, msg:Byte Ptr, size:Int, data:Object)
  279. Return TCurlEasy(data).dbFunction(TCurlEasy(data).dbData, infotype, String.fromBytes(msg, size))
  280. End Function
  281. ' +++++
  282. Rem
  283. bbdoc: Specify the stream to use for writing.
  284. about: Setting this will override a previous call to #setWriteCallback or #setWriteString.
  285. End Rem
  286. Method setWriteStream(stream:TStream)
  287. If easyHandlePtr Then
  288. bmx_curl_easy_setopt_ptr(easyHandlePtr, CURLOPT_WRITEFUNCTION, writeStreamCallback)
  289. bmx_curl_easy_setopt_obj(easyHandlePtr, CURLOPT_WRITEDATA, stream)
  290. End If
  291. End Method
  292. Function writeStreamCallback:Int(buffer:Byte Ptr, size:Int, nmemb:Int, stream:Object)
  293. Return TStream(stream).writeBytes(buffer, size * nmemb)
  294. End Function
  295. Rem
  296. bbdoc: Sets up a callback for writing (incoming data).
  297. about: This function gets called by libcurl as soon as there is data received that needs to be saved.
  298. The size of the data pointed to by @buffer is @size, it will not be zero terminated. Return the
  299. number of bytes actually taken care of. If that amount differs from the amount passed to your
  300. function, it'll signal an error to the library and it will abort the transfer and return
  301. #CURLE_WRITE_ERROR.
  302. <p>
  303. This function may be called with zero bytes data if the transfered file is empty.
  304. </p>
  305. <p>Setting this will override a previous call to #setWriteStream or #setWriteString.</p>
  306. End Rem
  307. Method setWriteCallback(writeFunction:Int(buffer:Byte Ptr, size:Int, data:Object), data:Object = Null)
  308. If easyHandlePtr Then
  309. wrFunction = writeFunction
  310. wrData = data
  311. bmx_curl_easy_setopt_ptr(easyHandlePtr, CURLOPT_WRITEFUNCTION, wrCallback)
  312. bmx_curl_easy_setopt_obj(easyHandlePtr, CURLOPT_WRITEDATA, Self)
  313. End If
  314. End Method
  315. ' +++++
  316. Field wrData:Object
  317. Field wrFunction:Int(buffer:Byte Ptr, size:Int, data:Object)
  318. Function wrCallback:Int(buffer:Byte Ptr, size:Int, nmemb:Int, data:Object)
  319. Return TCurlEasy(data).wrFunction(buffer, size * nmemb, TCurlEasy(data).wrData)
  320. End Function
  321. ' +++++
  322. Rem
  323. bbdoc: Data is retrieved into a String.
  324. about: Use toString() to get the data once the transfer is complete.
  325. <p>Setting this will override a previous call to #setWriteStream or #setWriteCallback.</p>
  326. End Rem
  327. Method setWriteString()
  328. data = Null
  329. setWriteCallback(writeStringFunction, Self)
  330. End Method
  331. Function writeStringFunction:Int(buffer:Byte Ptr, size:Int, curl:Object)
  332. TCurlEasy(curl).data:+ String.FromBytes( buffer, size )
  333. Return size
  334. End Function
  335. Rem
  336. bbdoc: Specify the stream to use for reading.
  337. about: Setting this will override a previous call to #setReadCallback.
  338. End Rem
  339. Method setReadStream(stream:TStream)
  340. If easyHandlePtr Then
  341. bmx_curl_easy_setopt_ptr(easyHandlePtr, CURLOPT_READFUNCTION, readStreamCallback)
  342. bmx_curl_easy_setopt_obj(easyHandlePtr, CURLOPT_READDATA, stream)
  343. End If
  344. End Method
  345. Function readStreamCallback:Int(buffer:Byte Ptr, size:Int, nmemb:Int, stream:Object)
  346. Try
  347. Return TStream(stream).read(buffer, size * nmemb)
  348. Catch e:TStreamReadException
  349. Return CURL_READFUNC_ABORT
  350. End Try
  351. End Function
  352. Rem
  353. bbdoc: Sets up a callback for reading (outgoing data).
  354. about: This function gets called by libcurl as soon as it needs to read data in order to send it
  355. to the peer. The data area pointed at by the buffer may be filled with at most @size bytes. Your
  356. function must return the actual number of bytes that you stored in that memory area.<br>
  357. Returning 0 will signal end-of-file to the library and cause it to stop the current transfer.
  358. <p>
  359. If you stop the current transfer by returning 0 "pre-maturely" (i.e before the server expected it,
  360. like when you've told you will upload N bytes and you upload less than N bytes), you may experience
  361. that the server "hangs" waiting for the rest of the data that won't come.
  362. </p>
  363. <p>
  364. The read callback may return #CURL_READFUNC_ABORT to stop the current operation immediately,
  365. resulting in a #CURLE_ABORTED_BY_CALLBACK error code from the transfer.
  366. </p>
  367. <p>Setting this will override a previous call to #setReadStream.</p>
  368. End Rem
  369. Method setReadCallback(readFunction:Int(buffer:Byte Ptr, size:Int, data:Object), data:Object = Null)
  370. If easyHandlePtr Then
  371. rdFunction = readFunction
  372. rdData = data
  373. bmx_curl_easy_setopt_ptr(easyHandlePtr, CURLOPT_READFUNCTION, rdCallback)
  374. bmx_curl_easy_setopt_obj(easyHandlePtr, CURLOPT_READDATA, Self)
  375. End If
  376. End Method
  377. ' +++++
  378. Field rdData:Object
  379. Field rdFunction:Int(buffer:Byte Ptr, size:Int, data:Object)
  380. Function rdCallback:Int(buffer:Byte Ptr, size:Int, nmemb:Int, data:Object)
  381. Return TCurlEasy(data).rdFunction(buffer, size * nmemb, TCurlEasy(data).rdData)
  382. End Function
  383. Rem
  384. bbdoc: Sets up a callback for header data (incoming).
  385. about: This function gets called by libcurl as soon as it has received header data. The header
  386. callback will be called once for each header and only complete header lines are passed on to the
  387. callback. Parsing headers should be easy enough using this. The size of the data pointed to by buffed
  388. is @size bytes. Do not assume that the header line is zero terminated! The callback function must
  389. return the number of bytes actually taken care of, or return -1 to signal error to the library
  390. (it will cause it to abort the transfer with a #CURLE_WRITE_ERROR return code).
  391. <p>
  392. When a server sends a chunked encoded transfer, it may contain a trailer. That trailer is identical
  393. to a HTTP header and if such a trailer is received it is passed to the application using this
  394. callback as well. There are several ways to detect it being a trailer and not an ordinary header:
  395. <ol>
  396. <li>it comes after the response-body.</li>
  397. <li>it comes after the final header line (CR LF)</li>
  398. <li>a Trailer: header among the response-headers mention what header to expect in the trailer.</li>
  399. </ol>
  400. </p>
  401. End Rem
  402. Method setHeaderCallback(headerFunction:Int(buffer:Byte Ptr, size:Int, data:Object), data:Object = Null)
  403. If easyHandlePtr Then
  404. hrFunction = headerFunction
  405. hrData = data
  406. bmx_curl_easy_setopt_ptr(easyHandlePtr, CURLOPT_HEADERFUNCTION, hrCallback)
  407. bmx_curl_easy_setopt_obj(easyHandlePtr, CURLOPT_WRITEHEADER, Self)
  408. End If
  409. End Method
  410. ' +++++
  411. Field hrData:Object
  412. Field hrFunction:Int(buffer:Byte Ptr, size:Int, data:Object)
  413. Function hrCallback:Int(buffer:Byte Ptr, size:Int, nmemb:Int, data:Object)
  414. Return TCurlEasy(data).hrFunction(buffer, size * nmemb, TCurlEasy(data).hrData)
  415. End Function
  416. ' +++++
  417. Rem
  418. bbdoc: Tells libcurl you want a multipart/formdata HTTP POST to be made, with the specified data in @formData.
  419. about: Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue" header. You can disable
  420. this header with #CURLOPT_HTTPHEADER as usual.
  421. <p>See #TCurlFormData for details of specific data. The #TCurlFormData object MUST be available until
  422. this curl object is cleaned up / deleted.</p>
  423. <p>
  424. Calling this method automatically sets #CURLOPT_NOBODY to 0.<br>
  425. Use this instead of setopt #CURLOPT_HTTPPOST.
  426. </p>
  427. End Rem
  428. Method httpPost(formData:TCurlFormData)
  429. If easyHandlePtr Then
  430. bmx_curl_easy_setopt_ptr(easyHandlePtr, CURLOPT_HTTPPOST, formData.httpPost.post);
  431. End If
  432. End Method
  433. Rem
  434. bbdoc: A list of HTTP headers to pass to the server in your HTTP request.
  435. about: If you add a header that is otherwise generated and used by libcurl internally, your added one will be
  436. used instead. If you add a header with no contents as in 'Accept:' (no data on the right side of the colon),
  437. the internally used header will get disabled. Thus, using this option you can add new headers, replace
  438. internal headers and remove internal headers. To add a header with no contents, make the contents be
  439. two quotes: "" (~q~q). The headers included in the list must not be CRLF-terminated, because curl
  440. adds CRLF after each header item. Failure to comply with this will result in strange bugs because the server
  441. will most likely ignore part of the headers you specified.
  442. <p>
  443. The first line in a request (containing the method, usually a GET or POST) is not a header and cannot be
  444. replaced using this option. Only the lines following the request-line are headers. Adding this method
  445. line in this list of headers will only cause your request to send an invalid header.
  446. </p>
  447. <p>Pass a Null to this to reset back to no custom headers.</p>
  448. <p>
  449. The most commonly replaced headers have "shortcuts" in the options #CURLOPT_COOKIE, #CURLOPT_USERAGENT and
  450. #CURLOPT_REFERER.
  451. <p>
  452. <p>Use this instead of setopt #CURLOPT_HTTPHEADER.</p>
  453. <p>After the call to #perform, you should call #freeLists to free up the internal structs.</p>
  454. End Rem
  455. Method httpHeader(headers:String[])
  456. If easyHandlePtr Then
  457. If headers Then
  458. processArray(CURLOPT_HTTPHEADER, headers)
  459. Else
  460. bmx_curl_easy_setopt_ptr(easyHandlePtr, CURLOPT_HTTPHEADER, Null)
  461. End If
  462. End If
  463. End Method
  464. Rem
  465. bbdoc: A list of aliases to be treated as valid HTTP 200 responses.
  466. about: Some servers respond with a custom header response line. For example, IceCast servers respond with
  467. "ICY 200 OK". By including this string in your list of aliases, the response will be treated as a
  468. valid HTTP header line such as "HTTP/1.0 200 OK".
  469. <p>
  470. The alias itself is not parsed for any version strings. The protocol is assumed to match HTTP 1.0 when an
  471. alias matched.
  472. </p>
  473. <p>Use this instead of setopt #CURLOPT_HTTP200ALIASES.</p>
  474. <p>After the call to #perform, you should call #freeLists to free up the internal structs.</p>
  475. End Rem
  476. Method http200Aliases(aliases:String[])
  477. If easyHandlePtr Then
  478. If aliases Then
  479. processArray(CURLOPT_HTTP200ALIASES, aliases)
  480. Else
  481. bmx_curl_easy_setopt_ptr(easyHandlePtr, CURLOPT_HTTP200ALIASES, Null)
  482. End If
  483. End If
  484. End Method
  485. Rem
  486. bbdoc: A list of FTP commands to pass to the server after the transfer type is set.
  487. about: Disable this operation again by passing Null to this method.
  488. <p>Use this instead of setopt #CURLOPT_PREQUOTE.</p>
  489. <p>After the call to #perform, you should call #freeLists to free up the internal structs.</p>
  490. End Rem
  491. Method preQuote(commands:String[])
  492. If easyHandlePtr Then
  493. If commands Then
  494. processArray(CURLOPT_PREQUOTE, commands)
  495. Else
  496. bmx_curl_easy_setopt_ptr(easyHandlePtr, CURLOPT_PREQUOTE, Null)
  497. End If
  498. End If
  499. End Method
  500. Rem
  501. bbdoc: A list of FTP or SFTP commands to pass to the server prior to your ftp request.
  502. about: This will be done before any other commands are issued (even before the CWD command for FTP).
  503. Disable this operation again by passing Null to this method. The valid SFTP commands are: chgrp, chmod, chown,
  504. ln, mkdir, pwd, rename, rm, rmdir, symlink.
  505. <p>Use this instead of setopt #CURLOPT_QUOTE.</p>
  506. <p>After the call to #perform, you should call #freeLists to free up the internal structs.</p>
  507. End Rem
  508. Method quote(commands:String[])
  509. If easyHandlePtr Then
  510. If commands Then
  511. processArray(CURLOPT_QUOTE, commands)
  512. Else
  513. bmx_curl_easy_setopt_ptr(easyHandlePtr, CURLOPT_QUOTE, Null)
  514. End If
  515. End If
  516. End Method
  517. Rem
  518. bbdoc: A list of FTP or SFTP commands to pass to the server after your ftp transfer request.
  519. about: Disable this operation again by passing Null to this method.
  520. <p>Use this instead of setopt #CURLOPT_POSTQUOTE.</p>
  521. <p>After the call to #perform, you should call #freeLists to free up the internal structs.</p>
  522. End Rem
  523. Method postQuote(commands:String[])
  524. If easyHandlePtr Then
  525. If commands Then
  526. processArray(CURLOPT_POSTQUOTE, commands)
  527. Else
  528. bmx_curl_easy_setopt_ptr(easyHandlePtr, CURLOPT_POSTQUOTE, Null)
  529. End If
  530. End If
  531. End Method
  532. Rem
  533. bbdoc: A list of Telnet variables to pass to the telnet negotiations.
  534. about: The variables should be in the format <option=value>. libcurl supports the options
  535. 'TTYPE', 'XDISPLOC' and 'NEW_ENV'. See the TELNET standard for details.
  536. <p>Use this instead of setopt #CURLOPT_TELNETOPTIONS.</p>
  537. <p>After the call to #perform, you should call #freeLists to free up the internal structs.</p>
  538. End Rem
  539. Method telnetOptions(variables:String[])
  540. If easyHandlePtr Then
  541. If variables Then
  542. processArray(CURLOPT_TELNETOPTIONS, variables)
  543. Else
  544. bmx_curl_easy_setopt_ptr(easyHandlePtr, CURLOPT_TELNETOPTIONS, Null)
  545. End If
  546. End If
  547. End Method
  548. Rem
  549. bbdoc: Returns a #TCurlInfo which provides access to internal curl session information.
  550. about: Use this method AFTER a performed transfer if you want to get transfer- oriented data.
  551. End Rem
  552. Method getInfo:TCurlInfo()
  553. If easyHandlePtr Then
  554. Return TCurlInfo._create(easyHandlePtr)
  555. End If
  556. Return Null
  557. End Method
  558. Rem
  559. bbdoc: Call this to free up the internal lists after calling #perform.
  560. about: The methods #httpHeader, #http200Aliases, #preQuote and #quote all create lists that are required to
  561. persist during #perform, but after which will need to be freed up.<br>
  562. Of course, if you intend reusing them for a subsequent perform, then don't call this method until you are ready.
  563. <p>
  564. This method is also called as part of #cleanup.
  565. </p>
  566. End Rem
  567. Method freeLists()
  568. Super.freeLists()
  569. End Method
  570. Rem
  571. bbdoc: Converts the given input string to an URL encoded string and returns that as a new allocated string.
  572. returns: The escaped string, or Null if it failed.
  573. about: All input characters that are not a-z, A-Z or 0-9 are converted to their "URL escaped" version
  574. (%NN where NN is a two-digit hexadecimal number).
  575. End Rem
  576. Method escape:String(Text:String)
  577. If easyHandlePtr Then
  578. If Not Text Then
  579. Text = ""
  580. End If
  581. Local s:Byte Ptr = Text.toUTF8String()
  582. Local s2:Byte Ptr = curl_easy_escape(easyHandlePtr, s, Text.length)
  583. ' free c string
  584. MemFree(s)
  585. If s2 Then
  586. Text = String.fromUTF8String(s2)
  587. ' free curl string
  588. curl_free(s2)
  589. Return Text
  590. End If
  591. End If
  592. Return Null
  593. End Method
  594. Rem
  595. bbdoc: Converts the given URL encoded input string to a "plain string" and returns that in an allocated memory area.
  596. returns: The unescaped string, or Null if it failed.
  597. about: All input characters that are URL encoded (%XX where XX is a two-digit hexadecimal number)
  598. are converted to their binary versions.
  599. End Rem
  600. Method unEscape:String(Text:String)
  601. If easyHandlePtr Then
  602. If Not Text Then
  603. Text = ""
  604. End If
  605. Local s:Byte Ptr = Text.toUTF8String()
  606. Local out:Int
  607. Local s2:Byte Ptr = curl_easy_unescape(easyHandlePtr, s, Text.length, Varptr out)
  608. ' free c string
  609. MemFree(s)
  610. If s2 Then
  611. Text = String.fromBytes(s2, out)
  612. ' free curl string
  613. curl_free(s2)
  614. Return Text
  615. End If
  616. End If
  617. Return Null
  618. End Method
  619. Rem
  620. bbdoc: Returns the contents of the transfer as a string, if #setWriteString was called.
  621. End Rem
  622. Method toString:String()
  623. Return data
  624. End Method
  625. Method Delete()
  626. cleanup()
  627. End Method
  628. Method processArray(option:Int, array:String[])
  629. If array And array.length > 0 Then
  630. Local sList:TSList = New TSList
  631. For Local i:Int = 0 Until array.length
  632. Local txt:Byte Ptr = array[i].toUTF8String()
  633. Local tmp:SCurlSlist Ptr = curl_slist_append(sList.slist, txt)
  634. If tmp Then
  635. sList.slist = tmp
  636. sList.count :+ 1
  637. End If
  638. MemFree(txt)
  639. Next
  640. bmx_curl_easy_setopt_slist(easyHandlePtr, option, sList.slist)
  641. sLists = sLists[..sLists.length + 1]
  642. sLists[sLists.length - 1] = sList
  643. End If
  644. End Method
  645. End Type
  646. ' internal :-)
  647. Type TCurlInt
  648. Field opt:Int
  649. Field s:Byte Ptr
  650. Function set:TCurlInt(opt:Int, s:Byte Ptr)
  651. Local this:TCurlInt = New TCurlInt
  652. this.opt = opt
  653. this.s = s
  654. Return this
  655. End Function
  656. End Type
  657. Rem
  658. bbdoc: Used to create a set of multipart/formdata for HTTP posts.
  659. about: This is used in conjunction with the #httpPost method.
  660. End Rem
  661. Type TCurlFormData Extends TCurlHasLists
  662. Field httppost:SCurlHttpPost
  663. Field count:Int = 0
  664. Field ptrs:Byte Ptr[] = New Byte Ptr[0]
  665. Rem
  666. bbdoc: Creates a new #TCurlFormData object
  667. End Rem
  668. Function Create:TCurlFormData()
  669. Local this:TCurlFormData = New TCurlFormData
  670. 'this.httppostPtr = bmx_curl_new_httppostPtr()
  671. Return this
  672. End Function
  673. Rem
  674. bbdoc: Add simple name/content section, with optional contenttype and/or headers.
  675. End Rem
  676. Method addContent(name:String, contents:String, contentType:String = Null, headers:String[] = Null)
  677. Local n:Byte Ptr = name.toUTF8String()
  678. Local c:Byte Ptr = contents.toUTF8String()
  679. Local t:Byte Ptr
  680. addPtr(n)
  681. addPtr(c)
  682. If contentType Then
  683. t = contentType.toUTF8String()
  684. addPtr(t)
  685. bmx_curl_formadd_name_content_type(httppost, n, c, t)
  686. Else
  687. bmx_curl_formadd_name_content(httppost, n, c)
  688. End If
  689. End Method
  690. Rem
  691. bbdoc: Add simple file section, with optional contenttype.
  692. End Rem
  693. Method addFile(name:String, file:String, contentType:String = Null, headers:String[] = Null)
  694. Local n:Byte Ptr = name.toUTF8String()
  695. Local f:Byte Ptr = file.toUTF8String()
  696. Local t:Byte Ptr
  697. addPtr(n)
  698. addPtr(f)
  699. If contentType Then
  700. t = contentType.toUTF8String()
  701. addPtr(t)
  702. bmx_curl_formadd_name_file_type(httppost, n, f, t, 1)
  703. Else
  704. bmx_curl_formadd_name_file(httppost, n, f, 1)
  705. End If
  706. End Method
  707. Rem
  708. bbdoc: Add the @content of a file as a normal post text value, with optional contenttype.
  709. End Rem
  710. Method addFileContent(name:String, file:String, contentType:String = Null, headers:String[] = Null)
  711. Local n:Byte Ptr = name.toUTF8String()
  712. Local f:Byte Ptr = file.toUTF8String()
  713. Local t:Byte Ptr
  714. addPtr(n)
  715. addPtr(f)
  716. If contentType Then
  717. t = contentType.toUTF8String()
  718. addPtr(t)
  719. bmx_curl_formadd_name_file_type(httppost, n, f, t, 2)
  720. Else
  721. bmx_curl_formadd_name_file(httppost, n, f, 2)
  722. End If
  723. End Method
  724. Rem
  725. bbdoc: Add a @buffer of @length bytes to the post.
  726. End Rem
  727. Method addBuffer(name:String, bufName:String, buffer:Byte Ptr, length:Int, headers:String[] = Null)
  728. Local n:Byte Ptr = name.toUTF8String()
  729. Local b:Byte Ptr = bufName.toUTF8String()
  730. addPtr(n)
  731. addPtr(b)
  732. bmx_curl_formadd_name_buffer(httppost, n, b, buffer, length)
  733. End Method
  734. Method addPtr(newPtr:Byte Ptr)
  735. ' extend if necessary
  736. If count = ptrs.length Then
  737. Local tmpPtrs:Byte Ptr[] = New Byte Ptr[ptrs.length + 5]
  738. For Local i:Int = 0 Until count
  739. tmpPtrs[i] = ptrs[i]
  740. Next
  741. ptrs = tmpPtrs
  742. End If
  743. ptrs[count] = newPtr
  744. count:+ 1
  745. End Method
  746. Method free()
  747. If httppost.post Then
  748. curl_formfree(httppost.post)
  749. httppost.post = Null
  750. End If
  751. If ptrs And count > 0 Then
  752. For Local i:Int = 0 Until count
  753. MemFree(ptrs[i])
  754. Next
  755. ptrs = Null
  756. End If
  757. freeLists()
  758. End Method
  759. Method Delete()
  760. free()
  761. End Method
  762. End Type
  763. Rem
  764. bbdoc: Retrieves internal information from a curl session, via the #getInfo method.
  765. about: This object will remain valid as long as the curl handle exists. You've been warned ;-)
  766. End Rem
  767. Type TCurlInfo
  768. Field easyHandlePtr:Byte Ptr
  769. Field error:Int
  770. Function _create:TCurlInfo(easyHandlePtr:Byte Ptr)
  771. Local this:TCurlInfo = New TCurlInfo
  772. this.easyHandlePtr = easyHandlePtr
  773. Return this
  774. End Function
  775. ?not win32
  776. Method activeSocket:Int()
  777. Local value:Int
  778. error = bmx_curl_easy_getinfo_int(easyHandlePtr, CURLINFO_ACTIVESOCKET, Varptr value)
  779. Return value
  780. End Method
  781. ?win32 and ptr32
  782. Method activeSocket:Int()
  783. Local value:Int
  784. error = bmx_curl_easy_getinfo_int(easyHandlePtr, CURLINFO_ACTIVESOCKET, Varptr value)
  785. Return value
  786. End Method
  787. ?win32 and ptr64
  788. Method activeSocket:Long()
  789. Local value:Long
  790. error = bmx_curl_easy_getinfo_long(easyHandlePtr, CURLINFO_ACTIVESOCKET, Varptr value)
  791. Return value
  792. End Method
  793. ?
  794. Rem
  795. bbdoc: The last used effective URL.
  796. End Rem
  797. Method effectiveURL:String()
  798. Local s:Byte Ptr
  799. error = bmx_curl_easy_getinfo_string(easyHandlePtr, CURLINFO_EFFECTIVE_URL, Varptr s)
  800. If Not error Then
  801. Return String.fromUTF8String(s)
  802. End If
  803. Return Null
  804. End Method
  805. Rem
  806. bbdoc: The last received HTTP or FTP code.
  807. about: This will be zero if no server response code has been received. Note that a proxy's CONNECT response
  808. should be read with #httpConnectCode and not this.
  809. End Rem
  810. Method responseCode:Int()
  811. Local value:Int
  812. error = bmx_curl_easy_getinfo_int(easyHandlePtr, CURLINFO_RESPONSE_CODE, Varptr value)
  813. Return value
  814. End Method
  815. Rem
  816. bbdoc: The last received proxy response code to a CONNECT request.
  817. End Rem
  818. Method httpConnectCode:Int()
  819. Local value:Int
  820. error = bmx_curl_easy_getinfo_int(easyHandlePtr, CURLINFO_HTTP_CONNECTCODE, Varptr value)
  821. Return value
  822. End Method
  823. Rem
  824. bbdoc: The remote time of the retrieved document (in number of seconds since 1 jan 1970 in the GMT/UTC time zone).
  825. about: If you get -1, it can be because of many reasons (unknown, the server hides it or the server doesn't
  826. support the command that tells document time etc) and the time of the document is unknown. Note that you must
  827. tell the server to collect this information before the transfer is made, by using the #CURLOPT_FILETIME option
  828. to #setOptInt or you will unconditionally get a -1 back.
  829. End Rem
  830. Method FileTime:Long()
  831. Local value:Long
  832. error = bmx_curl_easy_getinfo_long(easyHandlePtr, CURLINFO_FILETIME, Varptr value)
  833. Return value
  834. End Method
  835. Rem
  836. bbdoc: The total time in seconds for the previous transfer, including name resolving, TCP connect etc.
  837. End Rem
  838. Method totalTime:Double()
  839. Local value:Double
  840. error = bmx_curl_easy_getinfo_double(easyHandlePtr, CURLINFO_TOTAL_TIME, Varptr value)
  841. Return value
  842. End Method
  843. Rem
  844. bbdoc: The time, in seconds, it took from the start until the name resolving was completed.
  845. End Rem
  846. Method namelookupTime:Double()
  847. Local value:Double
  848. error = bmx_curl_easy_getinfo_double(easyHandlePtr, CURLINFO_NAMELOOKUP_TIME, Varptr value)
  849. Return value
  850. End Method
  851. Rem
  852. bbdoc: The time, in seconds, it took from the start until the connect to the remote host (or proxy) was completed.
  853. End Rem
  854. Method connectTime:Double()
  855. Local value:Double
  856. error = bmx_curl_easy_getinfo_double(easyHandlePtr, CURLINFO_CONNECT_TIME, Varptr value)
  857. Return value
  858. End Method
  859. Rem
  860. bbdoc: The time, in seconds, it took from the start until the file transfer is just about to begin.
  861. about: This includes all pre-transfer commands and negotiations that are specific to the particular
  862. protocol(s) involved.
  863. End Rem
  864. Method preTransferTime:Double()
  865. Local value:Double
  866. error = bmx_curl_easy_getinfo_double(easyHandlePtr, CURLINFO_PRETRANSFER_TIME, Varptr value)
  867. Return value
  868. End Method
  869. Rem
  870. bbdoc: The time, in seconds, it took from the start until the first byte is just about to be transferred.
  871. about: This includes #preTransferTime and also the time the server needs to calculate the result.
  872. End Rem
  873. Method startTransferTime:Double()
  874. Local value:Double
  875. error = bmx_curl_easy_getinfo_double(easyHandlePtr, CURLINFO_STARTTRANSFER_TIME, Varptr value)
  876. Return value
  877. End Method
  878. Rem
  879. bbdoc: The total time, in seconds, it took for all redirection steps include name lookup, connect, pretransfer and transfer before final transaction was started.
  880. about: Contains the complete execution time for multiple redirections.
  881. End Rem
  882. Method redirectTime:Double()
  883. Local value:Double
  884. error = bmx_curl_easy_getinfo_double(easyHandlePtr, CURLINFO_REDIRECT_TIME, Varptr value)
  885. Return value
  886. End Method
  887. Rem
  888. bbdoc: The total number of redirections that were actually followed.
  889. End Rem
  890. Method redirectCount:Int()
  891. Local value:Int
  892. error = bmx_curl_easy_getinfo_int(easyHandlePtr, CURLINFO_REDIRECT_COUNT, Varptr value)
  893. Return value
  894. End Method
  895. Rem
  896. bbdoc: The total amount of bytes that were uploaded.
  897. End Rem
  898. Method sizeUpload:Double()
  899. Local value:Double
  900. error = bmx_curl_easy_getinfo_double(easyHandlePtr, CURLINFO_SIZE_UPLOAD, Varptr value)
  901. Return value
  902. End Method
  903. Rem
  904. bbdoc: The total amount of bytes that were downloaded.
  905. about: The amount is only for the latest transfer and will be reset again for each new transfer.
  906. End Rem
  907. Method sizeDownload:Double()
  908. Local value:Double
  909. error = bmx_curl_easy_getinfo_double(easyHandlePtr, CURLINFO_SIZE_DOWNLOAD, Varptr value)
  910. Return value
  911. End Method
  912. Rem
  913. bbdoc: The average download speed that curl measured for the complete download.
  914. about: Measured in bytes/second.
  915. End Rem
  916. Method speedDownload:Double()
  917. Local value:Double
  918. error = bmx_curl_easy_getinfo_double(easyHandlePtr, CURLINFO_SPEED_DOWNLOAD, Varptr value)
  919. Return value
  920. End Method
  921. Rem
  922. bbdoc: The average upload speed that curl measured for the complete upload.
  923. about: Measured in bytes/second.
  924. End Rem
  925. Method speedUpload:Double()
  926. Local value:Double
  927. error = bmx_curl_easy_getinfo_double(easyHandlePtr, CURLINFO_SPEED_UPLOAD, Varptr value)
  928. Return value
  929. End Method
  930. Rem
  931. bbdoc: The total size of all the headers received.
  932. about: Measured in number of bytes.
  933. End Rem
  934. Method headerSize:Int()
  935. Local value:Int
  936. error = bmx_curl_easy_getinfo_int(easyHandlePtr, CURLINFO_HEADER_SIZE, Varptr value)
  937. Return value
  938. End Method
  939. Rem
  940. bbdoc: The total size of the issued requests.
  941. about: This is so far only for HTTP requests. Note that this may be more than one request if
  942. FOLLOWLOCATION is true.
  943. End Rem
  944. Method requestSize:Int()
  945. Local value:Int
  946. error = bmx_curl_easy_getinfo_int(easyHandlePtr, CURLINFO_REQUEST_SIZE, Varptr value)
  947. Return value
  948. End Method
  949. Rem
  950. bbdoc: The result of the certification verification that was requested (using the #CURLOPT_SSL_VERIFYPEER option).
  951. End Rem
  952. Method sslVerifyResult:Int()
  953. Local value:Int
  954. error = bmx_curl_easy_getinfo_int(easyHandlePtr, CURLINFO_SSL_VERIFYRESULT, Varptr value)
  955. Return value
  956. End Method
  957. Rem
  958. bbdoc: List of OpenSSL crypto-engines supported.
  959. about: Note that engines are normally implemented in separate dynamic libraries. Hence not all the returned
  960. engines may be available at run-time.
  961. End Rem
  962. Method sslEngines:String[]()
  963. Local slist:TSList = New TSList
  964. error = bmx_curl_easy_getinfo_slist(easyHandlePtr, CURLINFO_SSL_ENGINES, slist.slist)
  965. Return curlProcessSlist(slist)
  966. End Method
  967. Rem
  968. bbdoc: The content-length of the download.
  969. about: This is the value read from the Content-Length: field.
  970. End Rem
  971. Method contentLengthDownload:Double()
  972. Local value:Double
  973. error = bmx_curl_easy_getinfo_double(easyHandlePtr, CURLINFO_CONTENT_LENGTH_DOWNLOAD, Varptr value)
  974. Return value
  975. End Method
  976. Rem
  977. bbdoc: The specified size of the upload.
  978. End Rem
  979. Method contentLengthUpload:Double()
  980. Local value:Double
  981. error = bmx_curl_easy_getinfo_double(easyHandlePtr, CURLINFO_CONTENT_LENGTH_UPLOAD, Varptr value)
  982. Return value
  983. End Method
  984. Rem
  985. bbdoc: The content-type of the downloaded object.
  986. about: This is the value read from the Content-Type: field. If you get Null, it means that the server didn't
  987. send a valid Content-Type header or that the protocol used doesn't support this.
  988. End Rem
  989. Method contentType:String()
  990. Local s:Byte Ptr
  991. error = bmx_curl_easy_getinfo_string(easyHandlePtr, CURLINFO_CONTENT_TYPE, Varptr s)
  992. If Not error Then
  993. If s Then
  994. Return String.fromUTF8String(s)
  995. End If
  996. End If
  997. Return Null
  998. End Method
  999. Rem
  1000. bbdoc: The private data associated with the curl handle (set with the #setPrivate ).
  1001. End Rem
  1002. Method privateData:Object()
  1003. Return bmx_curl_easy_getinfo_obj(easyHandlePtr, CURLINFO_PRIVATE, Varptr error)
  1004. End Method
  1005. Rem
  1006. bbdoc: A bitmask indicating the authentication method(s) available.
  1007. about: The meaning of the bits is explained in the #CURLOPT_HTTPAUTH option
  1008. End Rem
  1009. Method httpAuthAvail:Int()
  1010. Local value:Int
  1011. error = bmx_curl_easy_getinfo_int(easyHandlePtr, CURLINFO_HTTPAUTH_AVAIL, Varptr value)
  1012. Return value
  1013. End Method
  1014. Rem
  1015. bbdoc: A bitmask indicating the authentication method(s) available for your proxy authentication.
  1016. about: The meaning of the bits is explained in the #CURLOPT_HTTPAUTH option
  1017. End Rem
  1018. Method proxyAuthAvail:Int()
  1019. Local value:Int
  1020. error = bmx_curl_easy_getinfo_int(easyHandlePtr, CURLINFO_PROXYAUTH_AVAIL, Varptr value)
  1021. Return value
  1022. End Method
  1023. Rem
  1024. bbdoc: The errno variable from a connect failure.
  1025. End Rem
  1026. Method osErrno:Int()
  1027. Local value:Int
  1028. error = bmx_curl_easy_getinfo_int(easyHandlePtr, CURLINFO_OS_ERRNO, Varptr value)
  1029. Return value
  1030. End Method
  1031. Rem
  1032. bbdoc: How many new connections libcurl had to create to achieve the previous transfer (only the successful connects are counted).
  1033. about: Combined with #redirectCount you are able to know how many times libcurl successfully reused existing
  1034. connection(s) or not.
  1035. End Rem
  1036. Method numConnects:Int()
  1037. Local value:Int
  1038. error = bmx_curl_easy_getinfo_int(easyHandlePtr, CURLINFO_NUM_CONNECTS, Varptr value)
  1039. Return value
  1040. End Method
  1041. Rem
  1042. bbdoc: A list of all cookies curl knows (expired ones, too).
  1043. about: If there are no cookies (cookies for the handle have not been enabled or simply none have been received),
  1044. the method returns Null.
  1045. End Rem
  1046. Method cookieList:String[]()
  1047. Local slist:TSList = New TSList
  1048. error = bmx_curl_easy_getinfo_slist(easyHandlePtr, CURLINFO_COOKIELIST, slist.slist)
  1049. Return curlProcessSlist(slist)
  1050. End Method
  1051. Rem
  1052. bbdoc: The last socket used by this curl session.
  1053. about: If the socket is no longer valid, -1 is returned. When you finish working with the socket,
  1054. you must call #cleanup as usual and let libcurl close the socket and cleanup other resources associated
  1055. with the handle. This is typically used in combination with #CURLOPT_CONNECT_ONLY.
  1056. End Rem
  1057. Method lastSocket:Int()
  1058. Local value:Int
  1059. error = bmx_curl_easy_getinfo_int(easyHandlePtr, CURLINFO_LASTSOCKET, Varptr value)
  1060. Return value
  1061. End Method
  1062. Rem
  1063. bbdoc: A string holding the path of the entry path.
  1064. about: That is the initial path libcurl ended up in when logging on to the remote FTP server.
  1065. This will return Null if something is wrong.
  1066. End Rem
  1067. Method ftpEntryPath:String()
  1068. Local s:Byte Ptr
  1069. error = bmx_curl_easy_getinfo_string(easyHandlePtr, CURLINFO_FTP_ENTRY_PATH, Varptr s)
  1070. If Not error Then
  1071. If s Then
  1072. Return String.fromUTF8String(s)
  1073. End If
  1074. End If
  1075. Return Null
  1076. End Method
  1077. Rem
  1078. bbdoc: If the operation was successful, CURLE_OK is returned, otherwise an appropriate error code will be returned.
  1079. End Rem
  1080. Method errorCode:Int()
  1081. Return error
  1082. End Method
  1083. End Type
  1084. Rem
  1085. bbdoc: The libcurl multi interface.
  1086. about: The multi interface offers several abilities that the easy interface doesn't. They are mainly:
  1087. <ul>
  1088. <li>Enable a "pull" interface. The application that uses libcurl decides where and when to ask libcurl
  1089. to get/send data.</li>
  1090. <li>Enable multiple simultaneous transfers in the same thread without making it complicated for the
  1091. application.</li>
  1092. <li>Enable the application to wait for action on its own file descriptors and curl's file descriptors
  1093. simultaneous easily.</li>
  1094. </ul>
  1095. <p>
  1096. Each single transfer is built up with a #TCurlEasy easy handle. You must create them, and setup the appropriate
  1097. options for each easy handle, using the usual "setOptXXX" methods.
  1098. </p>
  1099. <p>
  1100. When the easy handle is setup for a transfer, then instead of using #perform (as when using
  1101. the easy interface for transfers), you should instead add the easy handle to the multi handle
  1102. using #add. The multi handle is sometimes referred to as a 'multi stack' because of
  1103. the fact that it may hold a large amount of easy handles.
  1104. </p>
  1105. <p>
  1106. Should you change your mind, the easy handle is again removed from the multi stack using
  1107. #multiRemove. Once removed from the multi handle, you can again use other easy interface functions
  1108. like #perform on the handle or whatever you think is necessary.
  1109. </p>
  1110. <p>
  1111. Adding the easy handle to the multi handle does not start the transfer. Remember that one of the main
  1112. ideas with this interface is to let your application drive. You drive the transfers by invoking
  1113. #multiPerform. libcurl will then transfer data if there is anything available to transfer. It'll use
  1114. the callbacks and everything else you have setup in the individual easy handles. It'll transfer data
  1115. on all current transfers in the multi stack that are ready to transfer anything. It may be all, it may
  1116. be none.
  1117. </p>
  1118. <p>
  1119. Your application can acquire knowledge from libcurl when it would like to get invoked to transfer data,
  1120. so that you don't have to busy-loop and call that #multiPerform like crazy.
  1121. #multiSelect offers an interface which allows libcurl to know when the transfers in the multi stack might
  1122. need attention, without requiring your application to wait.
  1123. </p>
  1124. <p>
  1125. A little note here about the return codes from the multi functions, and especially the #multiPerform :
  1126. if you receive #CURLM_CALL_MULTI_PERFORM, this basically means that you should call #multiPerform again,
  1127. before you #multiSelect on more actions. You don't have to do it immediately, but the return code means
  1128. that libcurl may have more data available to return or that there may be more data to send off before
  1129. it is "satisfied".
  1130. </p>
  1131. <p>
  1132. #multiPerform stores the number of still running transfers in one of its input arguments,
  1133. and by reading that you can figure out when all the transfers in the multi handles are done.
  1134. 'done' does not mean successful. One or more of the transfers may have failed. Tracking when this number
  1135. changes, you know when one or more transfers are done.
  1136. </p>
  1137. <p>
  1138. To get information about completed transfers, to figure out success or not and similar,
  1139. #multiInfoRead should be called. It can return a message about a current or previous transfer.
  1140. Repeated invokes of the function get more messages until the message queue is empty. The information
  1141. you receive there includes an easy handle reference which you may use to identify which easy handle
  1142. the information regards.
  1143. </p>
  1144. <p>
  1145. When a single transfer is completed, the easy handle is still left added to the multi stack. You need to
  1146. first remove the easy handle with #multiRemove and then close it with #cleanup, or possibly set new options
  1147. to it and add it again with #multiAdd to start another transfer.
  1148. </p>
  1149. <p>
  1150. When all transfers in the multi stack are done, cleanup the multi handle with #multiCleanup. Be careful
  1151. and please note that you MUST invoke separate #cleanup calls on every single easy handle to clean
  1152. them up properly.
  1153. </p>
  1154. <p>
  1155. If you want to re-use an easy handle that was added to the multi handle for transfer, you must first
  1156. remove it from the multi stack and then re-add it again (possibly after having altered some options
  1157. at your own choice).
  1158. </p>
  1159. End Rem
  1160. Type TCurlMulti
  1161. Field multiHandlePtr:Byte Ptr
  1162. Field easyHandles:TList = New TList
  1163. Rem
  1164. bbdoc: Creates a new #TCurlMulti object.
  1165. End Rem
  1166. Function Create:TCurlMulti()
  1167. Local this:TCurlMulti = New TCurlMulti
  1168. this.multiHandlePtr = curl_multi_init()
  1169. If Not this.multiHandlePtr Then
  1170. Return Null
  1171. End If
  1172. Return this
  1173. End Function
  1174. Rem
  1175. bbdoc: Creates a new #TCurlEasy, automatically adding it to the multi stack.
  1176. returns: The new #TCurlEasy object.
  1177. End Rem
  1178. Method newEasy:TCurlEasy()
  1179. Local easy:TCurlEasy = TCurlEasy.Create()
  1180. multiAdd(easy)
  1181. Return easy
  1182. End Method
  1183. Rem
  1184. bbdoc: Adds a standard easy object to the multi stack.
  1185. about: This method call will make this multi handle control the specified easy handle.
  1186. <p>
  1187. When an easy object has been added to a multi stack, you can not and you must not use
  1188. #perform on that handle!
  1189. </p>
  1190. End Rem
  1191. Method multiAdd:Int(easy:TCurlEasy)
  1192. If multiHandlePtr And easy And easy.easyHandlePtr Then
  1193. easyHandles.addLast(easy)
  1194. Return curl_multi_add_handle(multiHandlePtr, easy.easyHandlePtr)
  1195. End If
  1196. End Method
  1197. Rem
  1198. bbdoc: Removes a given #TCurlEasy object from the multi handle.
  1199. about: This will make the specified easy handle be removed from this multi handle's control.
  1200. <p>
  1201. When the easy object has been removed from a multi stack, it is again perfectly legal to
  1202. invoke #perform on it.
  1203. </p>
  1204. <p>
  1205. Removing a handle while being used, will effectively halt all transfers in progress.
  1206. </p>
  1207. End Rem
  1208. Method multiRemove:Int(easy:TCurlEasy)
  1209. If multiHandlePtr And easy And easy.easyHandlePtr Then
  1210. ' remove from the list
  1211. easyHandles.remove(easy)
  1212. Return curl_multi_remove_handle(multiHandlePtr, easy.easyHandlePtr)
  1213. End If
  1214. End Method
  1215. Rem
  1216. bbdoc: Reads/writes available data from each easy handle.
  1217. about: When the app thinks there's data available for the multi handle, it should call this function
  1218. to read/write whatever there is to read or write right now. #multiPerform returns as soon as the
  1219. reads/writes are done. This function does not require that there actually is any data available
  1220. for reading or that data can be written, it can be called just in case. It will write the
  1221. number of handles that still transfer data in into @runningHandles.
  1222. <p>
  1223. When you call #multiPerform and the amount of @runningHandles is changed from the previous call
  1224. (or is less than the amount of easy handles you've added to the multi handle), you know that there
  1225. is one or more transfers less "running". You can then call #multiInfoRead to get information about
  1226. each individual completed transfer, and that returned info includes CURLcode and more.
  1227. </p>
  1228. <p>
  1229. If you receive #CURLM_CALL_MULTI_PERFORM, this basically means that you should call
  1230. #multiPerform again, before you #multiSelect on more actions. You don't have to do it immediately,
  1231. but the return code means that libcurl may have more data available to return or that there may be
  1232. more data to send off before it is "satisfied". Do note that #multiPerform will return
  1233. #CURLM_CALL_MULTI_PERFORM only when it wants to be called again immediately.
  1234. When things are fine and there are nothing immediate it wants done, it'll return #CURLM_OK and you
  1235. need to wait for "action" and then call this function again.
  1236. </p>
  1237. <p>
  1238. NOTE that this only returns errors etc regarding the whole multi stack. There might still have
  1239. occurred problems on individual transfers even when this function returns #CURLM_OK.
  1240. </p>
  1241. End Rem
  1242. Method multiPerform:Int(runningHandles:Int Var)
  1243. If multiHandlePtr Then
  1244. Return curl_multi_perform(multiHandlePtr, Varptr runningHandles)
  1245. End If
  1246. End Method
  1247. Rem
  1248. bbdoc: Waits for network connections to become ready, applying a @timeout seconds delay if required.
  1249. End Rem
  1250. Method multiSelect:Int(timeout:Double = 1.0)
  1251. If multiHandlePtr Then
  1252. Return bmx_curl_multiselect(multiHandlePtr, timeout)
  1253. End If
  1254. End Method
  1255. Rem
  1256. bbdoc: Close down a multi session.
  1257. about: Cleans up and removes a whole multi stack. It does not free or touch any individual
  1258. easy handles in any way - they still need to be closed individually, using the usual #cleanup way.
  1259. The order of cleaning up should be:
  1260. <ol>
  1261. <li>#multiRemove before any easy handles are cleaned up</li>
  1262. <li>#cleanup can now be called independently since the easy handle is no longer connected to the
  1263. multi handle</li>
  1264. <li>#multiCleanup should be called when all easy handles are removed</li>
  1265. </ol>
  1266. End Rem
  1267. Method multiCleanup()
  1268. If multiHandlePtr Then
  1269. If easyHandles Then
  1270. For Local easy:TCurlEasy = EachIn easyHandles
  1271. If easy.easyHandlePtr Then
  1272. curl_multi_remove_handle(multiHandlePtr, easy.easyHandlePtr)
  1273. End If
  1274. Next
  1275. End If
  1276. easyHandles.clear()
  1277. curl_multi_cleanup(multiHandlePtr)
  1278. multiHandlePtr = Null
  1279. End If
  1280. End Method
  1281. Rem
  1282. bbdoc: Ask the multi handle if there are any messages/informationals from the individual transfers.
  1283. about: Messages may include informationals such as an error code from the transfer or just the fact that a
  1284. transfer is completed. More details on these should be written down as well.
  1285. <p>
  1286. Repeated calls to this function will return a new #TCurlMultiMsg each time, until a Null is returned as a signal
  1287. that there is no more to get at this point. The integer pointed to messagesInQueue will contain the number of
  1288. remaining messages after this method was called.
  1289. </p>
  1290. <p>
  1291. When you fetch a message using this method, it is removed from the internal queue so calling this method again
  1292. will not return the same message again. It will instead return new messages at each new invoke until
  1293. the queue is emptied.
  1294. </p>
  1295. End Rem
  1296. Method multiInfoRead:TCurlMultiMsg(messagesInQueue:Int Var)
  1297. If multiHandlePtr Then
  1298. Local infoPtr:Byte Ptr = curl_multi_info_read(multiHandlePtr, Varptr messagesInQueue)
  1299. If infoPtr Then
  1300. Local info:TCurlMultiMsg = New TCurlMultiMsg
  1301. info.message = bmx_curl_CURLMsg_msg(infoPtr)
  1302. If info.message = CURLMSG_DONE Then
  1303. info.result = bmx_curl_CURLMsg_result(infoPtr)
  1304. End If
  1305. Local ePtr:Byte Ptr = bmx_curl_CURLMsg_easy_handle(infoPtr)
  1306. For Local e:TCurlEasy = EachIn easyHandles
  1307. If ePtr = e.easyHandlePtr Then
  1308. info.easy = e
  1309. Exit
  1310. End If
  1311. Next
  1312. Return info
  1313. End If
  1314. End If
  1315. Return Null
  1316. End Method
  1317. Rem
  1318. bbdoc: Used to tell a libcurl multi handle how to behave.
  1319. End Rem
  1320. Method multiSetOptInt(option:Int, parameter:Int)
  1321. If multiHandlePtr Then
  1322. bmx_curl_multi_setopt_int(multiHandlePtr, option, parameter)
  1323. End If
  1324. End Method
  1325. Method Delete()
  1326. multiCleanup()
  1327. End Method
  1328. End Type
  1329. Rem
  1330. bbdoc: A message type as retrieved from #multiInfoRead.
  1331. about: It provides specific information for finished transfers.
  1332. End Rem
  1333. Type TCurlMultiMsg
  1334. Rem
  1335. bbdoc: What this message means
  1336. End Rem
  1337. Field message:Int
  1338. Rem
  1339. bbdoc: The easy handle it concerns
  1340. End Rem
  1341. Field easy:TCurlEasy
  1342. Rem
  1343. bbdoc: Return code for transfer
  1344. End Rem
  1345. Field result:Int
  1346. End Type