@@ -14,6 +14,7 @@ ffi.cdef [[
1414 } curl_slist;
1515
1616 typedef size_t (* curl_write_callback )(char * ptr , size_t size , size_t nmemb , void * userdata );
17+ typedef int (* curl_xferinfo_callback )(void * clientp , curl_off_t dltotal , curl_off_t dlnow , curl_off_t ultotal , curl_off_t ulnow );
1718
1819 /* CURLoption values (CINIT macro: type*10000 + num) */
1920 /* OBJECTPOINT = 10000, FUNCTIONPOINT = 20000, LONG = 0, OFF_T = 30000 */
@@ -52,22 +53,24 @@ lib.curl_global_init(3) -- CURL_GLOBAL_ALL
5253
5354-- CURLoption constants
5455local OPT = {
55- URL = 10002 ,
56- WRITEFUNCTION = 20011 ,
57- WRITEDATA = 10001 ,
58- HTTPHEADER = 10023 ,
59- POSTFIELDS = 10015 ,
60- CUSTOMREQUEST = 10036 ,
61- FOLLOWLOCATION = 52 ,
62- TIMEOUT = 13 ,
63- VERBOSE = 41 ,
64- USERAGENT = 10018 ,
65- USERNAME = 10173 ,
66- PASSWORD = 10174 ,
67- SSL_VERIFYPEER = 64 ,
68- SSL_VERIFYHOST = 81 ,
69- CAINFO = 10065 ,
70- CAINFO_BLOB = 40309
56+ URL = 10002 ,
57+ WRITEFUNCTION = 20011 ,
58+ WRITEDATA = 10001 ,
59+ HTTPHEADER = 10023 ,
60+ POSTFIELDS = 10015 ,
61+ CUSTOMREQUEST = 10036 ,
62+ FOLLOWLOCATION = 52 ,
63+ TIMEOUT = 13 ,
64+ VERBOSE = 41 ,
65+ USERAGENT = 10018 ,
66+ USERNAME = 10173 ,
67+ PASSWORD = 10174 ,
68+ SSL_VERIFYPEER = 64 ,
69+ SSL_VERIFYHOST = 81 ,
70+ CAINFO = 10065 ,
71+ CAINFO_BLOB = 40309 ,
72+ NOPROGRESS = 43 ,
73+ XFERINFOFUNCTION = 20219
7174}
7275
7376-- on non-Windows, point curl at a CA bundle (bundled cacert.pem next to the lib, or system fallback)
@@ -113,6 +116,8 @@ local INFO = {
113116 EFFECTIVE_URL = 0x100001
114117}
115118
119+ --- @alias CurlProgressCallback fun ( dltotal : number , dlnow : number , ultotal : number , ulnow : number ): boolean | number | nil
120+
116121--- @class CurlResponse
117122--- @field status number HTTP status code
118123--- @field body string Response body
@@ -132,6 +137,7 @@ local INFO = {
132137--- @field username string | nil Username for auth
133138--- @field password string | nil Password for auth
134139--- @field verifySsl boolean | nil Verify SSL cert (default : true )
140+ --- @field progress CurlProgressCallback | nil Progress callback ; return truthy to abort
135141
136142-- pre-allocated output slots reused across requests
137143local statusOut = ffi .new (" long[1]" )
@@ -179,6 +185,15 @@ local function request(opts)
179185 if opts .username then lib .curl_easy_setopt (handle , OPT .USERNAME , opts .username ) end
180186 if opts .password then lib .curl_easy_setopt (handle , OPT .PASSWORD , opts .password ) end
181187
188+ local progressCb
189+ if opts .progress then
190+ progressCb = ffi .cast (" curl_xferinfo_callback" , function (_ , dltotal , dlnow , ultotal , ulnow )
191+ return opts .progress (tonumber (dltotal ), tonumber (dlnow ), tonumber (ultotal ), tonumber (ulnow )) and 1 or 0
192+ end )
193+ setlong (OPT .NOPROGRESS , 0 )
194+ lib .curl_easy_setopt (handle , OPT .XFERINFOFUNCTION , progressCb )
195+ end
196+
182197 -- headers
183198 local slist = nil
184199 if opts .headers then
@@ -274,6 +289,17 @@ function curl.download(url, path, opts)
274289 lib .curl_easy_setopt (handle , OPT .CAINFO_BLOB , defaultCainfoBlob )
275290 end
276291 lib .curl_easy_setopt (handle , OPT .WRITEDATA , f )
292+
293+ local progressCb
294+ if opts and opts .progress then
295+ progressCb = ffi .cast (" curl_xferinfo_callback" , function (_ , dltotal , dlnow , ultotal , ulnow )
296+ return opts .progress (tonumber (dltotal ), tonumber (dlnow ), tonumber (ultotal ), tonumber (ulnow )) and 1 or 0
297+ end )
298+
299+ setlong (OPT .NOPROGRESS , 0 )
300+ lib .curl_easy_setopt (handle , OPT .XFERINFOFUNCTION , progressCb )
301+ end
302+
277303 local code = lib .curl_easy_perform (handle )
278304 ffi .C .fclose (f )
279305
0 commit comments