Skip to content

Commit 9a7fd63

Browse files
committed
Merge pull request #47 from moteus/master
Fix. cURL API may return lcurl raw handle
2 parents 1747a35 + 1738369 commit 9a7fd63

File tree

9 files changed

+236
-42
lines changed

9 files changed

+236
-42
lines changed

doc/curl.ldoc

+17
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,17 @@ do
135135
-- e:perfom{writefunction = assert(io.open("fname.txt", "w+b"))}
136136
function perfom() end
137137

138+
--- User data.
139+
--
140+
-- Please use this field to associate any data with curl handle.
141+
--
142+
-- @field data
143+
--
144+
-- @usage
145+
-- f = io.open("lua.org.download", "w+")
146+
-- e = curl.easy{url = "http://lua.org", writefunction = f}
147+
-- e.data = f
148+
138149
end
139150

140151
--- Muli curl object
@@ -155,4 +166,10 @@ do
155166
-- for data, type, easy in m:iperform() do ... end
156167
function iperform() end
157168

169+
--- User data.
170+
--
171+
-- Please use this field to associate any data with curl handle.
172+
--
173+
-- @field data
174+
158175
end

examples/cURLv3/multi-uv.lua

+25-26
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,11 @@ local FLAGS = {
2727

2828
}
2929

30-
local trace = function() end or print
30+
local trace = true
3131

32-
local FILES, CONTEXT = {}, {}
32+
trace = trace and print or function() end
33+
34+
local CONTEXT = {}
3335

3436
function create_curl_context(sockfd)
3537
local context = {
@@ -58,22 +60,22 @@ function add_download(url, num)
5860
writefunction = file;
5961
}
6062

61-
FILES[handle] = file
63+
handle.data = file
6264

6365
curl_handle:add_handle(handle)
6466
fprintf(stderr, "Added download %s -> %s\n", url, filename);
6567
end
6668

6769
function check_multi_info()
6870
while true do
69-
local easy, ok, err = curl_handle:info_read()
71+
local easy, ok, err = curl_handle:info_read(true)
7072
if not easy then curl_handle:close() error(err) end
7173
if easy == 0 then break end
7274

7375
local context = CONTEXT[e]
7476
if context then destroy_curl_context(context) end
75-
local file = FILES[easy]
76-
if file then FILES[easy] = nil, file:close() end
77+
local file = assert(easy.data)
78+
file:close()
7779
local done_url = easy:getinfo_effective_url()
7880
easy:close()
7981
if ok then
@@ -116,29 +118,26 @@ function start_timeout(timeout_ms)
116118
timeout:stop():start(timeout_ms, 0, on_timeout)
117119
end
118120

119-
local handle_socket = function(...)
120-
local ok, err = pcall(handle_socket_impl, ...)
121-
if not ok then uv.defer(function() error(err) end) end
122-
end
123-
124-
function handle_socket_impl(easy, s, action)
125-
-- calls by curl --
121+
function handle_socket(easy, s, action)
122+
local ok, err = pcall(function()
123+
-- calls by curl --
124+
trace("CURL::SOCKET", easy, s, ACTION_NAMES[action] or action)
126125

127-
trace("CURL::SOCKET", easy, s, ACTION_NAMES[action] or action)
126+
local curl_context = CONTEXT[easy] or create_curl_context(s)
127+
CONTEXT[easy] = curl_context
128128

129-
local curl_context = CONTEXT[easy] or create_curl_context(s)
130-
CONTEXT[easy] = curl_context
129+
assert(curl_context.sockfd == s)
131130

132-
assert(curl_context.sockfd == s)
133-
134-
if action == curl.POLL_IN then
135-
curl_context.poll_handle:start(uv.READABLE, curl_perform)
136-
elseif action == curl.POLL_OUT then
137-
curl_context.poll_handle:start(uv.WRITABLE, curl_perform)
138-
elseif action == curl.POLL_REMOVE then
139-
CONTEXT[easy] = nil
140-
destroy_curl_context(curl_context)
141-
end
131+
if action == curl.POLL_IN then
132+
curl_context.poll_handle:start(uv.READABLE, curl_perform)
133+
elseif action == curl.POLL_OUT then
134+
curl_context.poll_handle:start(uv.WRITABLE, curl_perform)
135+
elseif action == curl.POLL_REMOVE then
136+
CONTEXT[easy] = nil
137+
destroy_curl_context(curl_context)
138+
end
139+
end)
140+
if not ok then uv.defer(function() error(err) end) end
142141
end
143142

144143
timeout = uv.timer()

src/lceasy.c

+23
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ static int lcurl_easy_cleanup(lua_State *L){
100100
p->lists[i] = LUA_NOREF;
101101
}
102102

103+
lua_settop(L, 1);
104+
lua_pushnil(L);
105+
lua_rawset(L, LCURL_USERVALUES);
106+
103107
return 0;
104108
}
105109

@@ -941,6 +945,22 @@ static int lcurl_easy_pause(lua_State *L){
941945
return 1;
942946
}
943947

948+
static int lcurl_easy_setdata(lua_State *L){
949+
lcurl_easy_t *p = lcurl_geteasy(L);
950+
lua_settop(L, 2);
951+
lua_pushvalue(L, 1);
952+
lua_insert(L, 2);
953+
lua_rawset(L, LCURL_USERVALUES);
954+
return 1;
955+
}
956+
957+
static int lcurl_easy_getdata(lua_State *L){
958+
lcurl_easy_t *p = lcurl_geteasy(L);
959+
lua_settop(L, 1);
960+
lua_rawget(L, LCURL_USERVALUES);
961+
return 1;
962+
}
963+
944964
//}
945965

946966
static const struct luaL_Reg lcurl_easy_methods[] = {
@@ -982,6 +1002,9 @@ static const struct luaL_Reg lcurl_easy_methods[] = {
9821002
{ "close", lcurl_easy_cleanup },
9831003
{ "__gc", lcurl_easy_cleanup },
9841004

1005+
{ "setdata", lcurl_easy_setdata },
1006+
{ "getdata", lcurl_easy_getdata },
1007+
9851008
{NULL,NULL}
9861009
};
9871010

src/lcmulti.c

+24
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ static int lcurl_multi_cleanup(lua_State *L){
7878
luaL_unref(L, LCURL_LUA_REGISTRY, p->sc.ud_ref);
7979
p->tm.cb_ref = p->tm.ud_ref = LUA_NOREF;
8080
p->sc.cb_ref = p->sc.ud_ref = LUA_NOREF;
81+
82+
lua_settop(L, 1);
83+
lua_pushnil(L);
84+
lua_rawset(L, LCURL_USERVALUES);
85+
8186
return 0;
8287
}
8388

@@ -441,6 +446,22 @@ static int lcurl_multi_setopt(lua_State *L){
441446
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_MULTI, CURLM_UNKNOWN_OPTION);
442447
}
443448

449+
static int lcurl_multi_setdata(lua_State *L){
450+
lcurl_multi_t *p = lcurl_getmulti(L);
451+
lua_settop(L, 2);
452+
lua_pushvalue(L, 1);
453+
lua_insert(L, 2);
454+
lua_rawset(L, LCURL_USERVALUES);
455+
return 1;
456+
}
457+
458+
static int lcurl_multi_getdata(lua_State *L){
459+
lcurl_multi_t *p = lcurl_getmulti(L);
460+
lua_settop(L, 1);
461+
lua_rawget(L, LCURL_USERVALUES);
462+
return 1;
463+
}
464+
444465
//}
445466

446467
static const struct luaL_Reg lcurl_multi_methods[] = {
@@ -459,6 +480,9 @@ static const struct luaL_Reg lcurl_multi_methods[] = {
459480
OPT_ENTRY(socketfunction, SOCKETFUNCTION, TTT, 0)
460481
#undef OPT_ENTRY
461482

483+
{ "setdata", lcurl_multi_setdata },
484+
{ "getdata", lcurl_multi_getdata },
485+
462486
{"close", lcurl_multi_cleanup },
463487
{"__gc", lcurl_multi_cleanup },
464488

src/lcurl.c

+16-7
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ static const lcurl_const_t lcurl_flags[] = {
180180
static volatile int LCURL_INIT = 0;
181181

182182
static const char* LCURL_REGISTRY = "LCURL Registry";
183+
static const char* LCURL_USERVAL = "LCURL Uservalues";
183184

184185
static int luaopen_lcurl_(lua_State *L, const struct luaL_Reg *func){
185186
if(!LCURL_INIT){
@@ -192,16 +193,24 @@ static int luaopen_lcurl_(lua_State *L, const struct luaL_Reg *func){
192193
lua_pop(L, 1);
193194
lua_newtable(L);
194195
}
196+
197+
lua_rawgetp(L, LUA_REGISTRYINDEX, LCURL_USERVAL);
198+
if(!lua_istable(L, -1)){ /* usevalues */
199+
lua_pop(L, 1);
200+
lcurl_util_new_weak_table(L, "k");
201+
}
202+
195203
lua_newtable(L); /* library */
196204

197-
lua_pushvalue(L, -2); luaL_setfuncs(L, func, 1);
198-
lua_pushvalue(L, -2); lcurl_error_initlib(L, 1);
199-
lua_pushvalue(L, -2); lcurl_hpost_initlib(L, 1);
200-
lua_pushvalue(L, -2); lcurl_easy_initlib (L, 1);
201-
lua_pushvalue(L, -2); lcurl_multi_initlib(L, 1);
202-
lua_pushvalue(L, -2); lcurl_share_initlib(L, 1);
205+
lua_pushvalue(L, -3); lua_pushvalue(L, -3); luaL_setfuncs(L, func, 2);
206+
lua_pushvalue(L, -3); lua_pushvalue(L, -3); lcurl_error_initlib(L, 2);
207+
lua_pushvalue(L, -3); lua_pushvalue(L, -3); lcurl_hpost_initlib(L, 2);
208+
lua_pushvalue(L, -3); lua_pushvalue(L, -3); lcurl_easy_initlib (L, 2);
209+
lua_pushvalue(L, -3); lua_pushvalue(L, -3); lcurl_multi_initlib(L, 2);
210+
lua_pushvalue(L, -3); lua_pushvalue(L, -3); lcurl_share_initlib(L, 2);
203211

204-
lua_pushvalue(L, -2); lua_rawsetp(L, LUA_REGISTRYINDEX, LCURL_REGISTRY);
212+
lua_pushvalue(L, -3); lua_rawsetp(L, LUA_REGISTRYINDEX, LCURL_REGISTRY);
213+
lua_pushvalue(L, -2); lua_rawsetp(L, LUA_REGISTRYINDEX, LCURL_USERVAL);
205214

206215
lua_remove(L, -2); /* registry */
207216

src/lcurl.h

+1
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@
2323

2424
#define LCURL_LUA_REGISTRY lua_upvalueindex(1)
2525

26+
#define LCURL_USERVALUES lua_upvalueindex(2)
2627

2728
#endif

src/lua/cURL/impl/cURL.lua

+84-9
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,8 @@ local function make_iterator(self, perform)
9999

100100
if n <= remain then
101101
while true do
102-
local h, ok, err = assert(self:info_read())
103-
if h == 0 then break end
104-
local e = assert(self._easy[h])
102+
local e, ok, err = assert(self:info_read())
103+
if e == 0 then break end
105104
if ok then
106105
ok = e:getinfo_response_code() or ok
107106
buffers:append(e, "done", ok)
@@ -423,6 +422,22 @@ function Multi:remove_handle(e)
423422
return remove_handle(self, h)
424423
end
425424

425+
function Multi:info_read(...)
426+
while true do
427+
local h, ok, err = self:handle():info_read(...)
428+
if not h then return nil, ok end
429+
if h == 0 then return h end
430+
431+
local e = self._easy[h]
432+
if e then
433+
if ... then
434+
self._easy[h], self._easy.n = nil, self._easy.n - 1
435+
end
436+
return e, ok, err
437+
end
438+
end
439+
end
440+
426441
end
427442
-------------------------------------------
428443

@@ -556,14 +571,74 @@ function Multi:remove_handle(e)
556571
end
557572

558573
function Multi:info_read(...)
559-
local h, ok, err = self:handle():info_read(...)
560-
if not h then return nil, ok end
561-
if h == 0 then return h end
574+
while true do
575+
local h, ok, err = self:handle():info_read(...)
576+
if not h then return nil, ok end
577+
if h == 0 then return h end
578+
579+
local e = self._easy[h]
580+
if e then
581+
if ... then
582+
self._easy[h], self._easy.n = nil, self._easy.n - 1
583+
end
584+
return e, ok, err
585+
end
586+
end
587+
end
562588

563-
if ... and self._easy[h] then
564-
self._easy[h], self._easy.n = nil, self._easy.n - 1
589+
function wrap_callback(...)
590+
local n = select("#", ...)
591+
local fn, ctx, has_ctx
592+
if n >= 2 then
593+
has_ctx, fn, ctx = true, assert(...)
594+
else
595+
fn = assert(...)
596+
if type(fn) ~= "function" then
597+
has_ctx, fn, ctx = true, assert(fn.socket), fn
598+
end
599+
end
600+
if has_ctx then
601+
return function(...) return fn(ctx, ...) end
565602
end
566-
return h, ok, err
603+
return function(...) return fn(...) end
604+
end
605+
606+
function wrap_socketfunction(self, cb)
607+
return function(h, ...)
608+
local e = self._easy[h]
609+
if e then return cb(e, ...) end
610+
return 0
611+
end
612+
end
613+
614+
local setopt_socketfunction = wrap_function("setopt_socketfunction")
615+
function Multi:setopt_socketfunction(...)
616+
local cb = wrap_callback(...)
617+
618+
return setopt_socketfunction(wrap_socketfunction(self, cb))
619+
end
620+
621+
local setopt = wrap_function("setopt")
622+
function Multi:setopt(k, v)
623+
if type(k) == 'table' then
624+
local t = k
625+
626+
local socketfunction = t.socketfunction or t[curl.OPT_SOCKETFUNCTION]
627+
if socketfunction then
628+
t = clone(t)
629+
local fn = wrap_socketfunction(self, socketfunction)
630+
if t.socketfunction then t.socketfunction = fn end
631+
if t[curl.OPT_SOCKETFUNCTION] then t[curl.OPT_SOCKETFUNCTION] = fn end
632+
end
633+
634+
return setopt(self, t)
635+
end
636+
637+
if k == curl.OPT_SOCKETFUNCTION then
638+
return self:setopt_httppost(wrap_socketfunction(v))
639+
end
640+
641+
return setopt(self, k, v)
567642
end
568643

569644
end

test/test_curl.lua

+14
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,20 @@ function test_add_handle()
9393
assert_nil(c)
9494
end
9595

96+
function test_info_read()
97+
local url = 'http://httpbin.org/get?key=1'
98+
c = assert(curl.easy{url=url, writefunction=function() end})
99+
assert_equal(m, m:add_handle(c))
100+
101+
while m:perform() > 0 do m:wait() end
102+
103+
local h, ok, err = m:info_read()
104+
assert_equal(c, h)
105+
106+
local h, ok, err = m:info_read()
107+
assert_equal(0, h)
108+
end
109+
96110
end
97111

98112
local _ENV = TEST_CASE'form' if ENABLE then

0 commit comments

Comments
 (0)